Full Code of sqshq/piggymetrics for AI

master 6bb2cf9ddbca cached
166 files
455.9 KB
135.8k tokens
521 symbols
1 requests
Download .txt
Showing preview only (509K chars total). Download the full file or copy to clipboard to get everything.
Repository: sqshq/piggymetrics
Branch: master
Commit: 6bb2cf9ddbca
Files: 166
Total size: 455.9 KB

Directory structure:
gitextract_15q1n21c/

├── .github/
│   └── ISSUE_TEMPLATE/
│       └── bug-report-or-feature-request.md
├── .gitignore
├── .travis.yml
├── LICENCE
├── README.md
├── account-service/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── account/
│       │   │               ├── AccountApplication.java
│       │   │               ├── client/
│       │   │               │   ├── AuthServiceClient.java
│       │   │               │   ├── StatisticsServiceClient.java
│       │   │               │   └── StatisticsServiceClientFallback.java
│       │   │               ├── config/
│       │   │               │   └── ResourceServerConfig.java
│       │   │               ├── controller/
│       │   │               │   ├── AccountController.java
│       │   │               │   └── ErrorHandler.java
│       │   │               ├── domain/
│       │   │               │   ├── Account.java
│       │   │               │   ├── Currency.java
│       │   │               │   ├── Item.java
│       │   │               │   ├── Saving.java
│       │   │               │   ├── TimePeriod.java
│       │   │               │   └── User.java
│       │   │               ├── repository/
│       │   │               │   └── AccountRepository.java
│       │   │               └── service/
│       │   │                   ├── AccountService.java
│       │   │                   ├── AccountServiceImpl.java
│       │   │                   └── security/
│       │   │                       └── CustomUserInfoTokenServices.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── account/
│           │               ├── AccountServiceApplicationTests.java
│           │               ├── client/
│           │               │   └── StatisticsServiceClientFallbackTest.java
│           │               ├── controller/
│           │               │   └── AccountControllerTest.java
│           │               ├── repository/
│           │               │   └── AccountRepositoryTest.java
│           │               └── service/
│           │                   └── AccountServiceTest.java
│           └── resources/
│               ├── application.yml
│               └── bootstrap.yml
├── auth-service/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── auth/
│       │   │               ├── AuthApplication.java
│       │   │               ├── config/
│       │   │               │   ├── OAuth2AuthorizationConfig.java
│       │   │               │   └── WebSecurityConfig.java
│       │   │               ├── controller/
│       │   │               │   └── UserController.java
│       │   │               ├── domain/
│       │   │               │   └── User.java
│       │   │               ├── repository/
│       │   │               │   └── UserRepository.java
│       │   │               └── service/
│       │   │                   ├── UserService.java
│       │   │                   ├── UserServiceImpl.java
│       │   │                   └── security/
│       │   │                       └── MongoUserDetailsService.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── auth/
│           │               ├── AuthServiceApplicationTests.java
│           │               ├── controller/
│           │               │   └── UserControllerTest.java
│           │               ├── repository/
│           │               │   └── UserRepositoryTest.java
│           │               └── service/
│           │                   ├── UserServiceTest.java
│           │                   └── security/
│           │                       └── MongoUserDetailsServiceTest.java
│           └── resources/
│               ├── application.yml
│               └── bootstrap.yml
├── config/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── config/
│           │               ├── ConfigApplication.java
│           │               └── SecurityConfig.java
│           └── resources/
│               ├── application.yml
│               └── shared/
│                   ├── account-service.yml
│                   ├── application.yml
│                   ├── auth-service.yml
│                   ├── gateway.yml
│                   ├── monitoring.yml
│                   ├── notification-service.yml
│                   ├── registry.yml
│                   ├── statistics-service.yml
│                   └── turbine-stream-service.yml
├── docker-compose.dev.yml
├── docker-compose.yml
├── gateway/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── gateway/
│       │   │               └── GatewayApplication.java
│       │   └── resources/
│       │       ├── bootstrap.yml
│       │       └── static/
│       │           ├── attribution.html
│       │           ├── css/
│       │           │   ├── animation.css
│       │           │   ├── launch.css
│       │           │   └── style.css
│       │           ├── index.html
│       │           └── js/
│       │               ├── dashboard.js
│       │               ├── launch.js
│       │               ├── lib/
│       │               │   ├── extrascripts.js
│       │               │   └── touchscreens.js
│       │               ├── login.js
│       │               └── main.js
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── gateway/
│           │               └── GatewayApplicationTests.java
│           └── resources/
│               └── bootstrap.yml
├── mongodb/
│   ├── Dockerfile
│   ├── dump/
│   │   └── account-service-dump.js
│   └── init.sh
├── monitoring/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── monitoring/
│       │   │               └── MonitoringApplication.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── monitoring/
│           │               └── MonitoringApplicationTests.java
│           └── resources/
│               └── bootstrap.yml
├── notification-service/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── notification/
│       │   │               ├── NotificationServiceApplication.java
│       │   │               ├── client/
│       │   │               │   └── AccountServiceClient.java
│       │   │               ├── config/
│       │   │               │   └── ResourceServerConfig.java
│       │   │               ├── controller/
│       │   │               │   └── RecipientController.java
│       │   │               ├── domain/
│       │   │               │   ├── Frequency.java
│       │   │               │   ├── NotificationSettings.java
│       │   │               │   ├── NotificationType.java
│       │   │               │   └── Recipient.java
│       │   │               ├── repository/
│       │   │               │   ├── RecipientRepository.java
│       │   │               │   └── converter/
│       │   │               │       ├── FrequencyReaderConverter.java
│       │   │               │       └── FrequencyWriterConverter.java
│       │   │               └── service/
│       │   │                   ├── EmailService.java
│       │   │                   ├── EmailServiceImpl.java
│       │   │                   ├── NotificationService.java
│       │   │                   ├── NotificationServiceImpl.java
│       │   │                   ├── RecipientService.java
│       │   │                   └── RecipientServiceImpl.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── notification/
│           │               ├── NotificationServiceApplicationTests.java
│           │               ├── controller/
│           │               │   └── RecipientControllerTest.java
│           │               ├── repository/
│           │               │   └── RecipientRepositoryTest.java
│           │               └── service/
│           │                   ├── EmailServiceImplTest.java
│           │                   ├── NotificationServiceImplTest.java
│           │                   └── RecipientServiceImplTest.java
│           └── resources/
│               ├── application.yml
│               └── bootstrap.yml
├── pom.xml
├── registry/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── registry/
│           │               └── RegistryApplication.java
│           └── resources/
│               └── bootstrap.yml
├── statistics-service/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── statistics/
│       │   │               ├── StatisticsApplication.java
│       │   │               ├── client/
│       │   │               │   ├── ExchangeRatesClient.java
│       │   │               │   └── ExchangeRatesClientFallback.java
│       │   │               ├── config/
│       │   │               │   └── ResourceServerConfig.java
│       │   │               ├── controller/
│       │   │               │   └── StatisticsController.java
│       │   │               ├── domain/
│       │   │               │   ├── Account.java
│       │   │               │   ├── Currency.java
│       │   │               │   ├── ExchangeRatesContainer.java
│       │   │               │   ├── Item.java
│       │   │               │   ├── Saving.java
│       │   │               │   ├── TimePeriod.java
│       │   │               │   └── timeseries/
│       │   │               │       ├── DataPoint.java
│       │   │               │       ├── DataPointId.java
│       │   │               │       ├── ItemMetric.java
│       │   │               │       └── StatisticMetric.java
│       │   │               ├── repository/
│       │   │               │   ├── DataPointRepository.java
│       │   │               │   └── converter/
│       │   │               │       ├── DataPointIdReaderConverter.java
│       │   │               │       └── DataPointIdWriterConverter.java
│       │   │               └── service/
│       │   │                   ├── ExchangeRatesService.java
│       │   │                   ├── ExchangeRatesServiceImpl.java
│       │   │                   ├── StatisticsService.java
│       │   │                   ├── StatisticsServiceImpl.java
│       │   │                   └── security/
│       │   │                       └── CustomUserInfoTokenServices.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── statistics/
│           │               ├── StatisticsServiceApplicationTests.java
│           │               ├── client/
│           │               │   └── ExchangeRatesClientTest.java
│           │               ├── controller/
│           │               │   └── StatisticsControllerTest.java
│           │               ├── repository/
│           │               │   └── DataPointRepositoryTest.java
│           │               └── service/
│           │                   ├── ExchangeRatesServiceImplTest.java
│           │                   └── StatisticsServiceImplTest.java
│           └── resources/
│               ├── application.yml
│               └── bootstrap.yml
└── turbine-stream-service/
    ├── Dockerfile
    ├── pom.xml
    └── src/
        ├── main/
        │   ├── java/
        │   │   └── com/
        │   │       └── piggymetrics/
        │   │           └── turbine/
        │   │               └── TurbineStreamServiceApplication.java
        │   └── resources/
        │       └── bootstrap.yml
        └── test/
            ├── java/
            │   └── com/
            │       └── piggymetrics/
            │           └── turbine/
            │               └── TurbineStreamServiceApplicationTests.java
            └── resources/
                └── bootstrap.yml

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

================================================
FILE: .github/ISSUE_TEMPLATE/bug-report-or-feature-request.md
================================================
---
name: Bug report or feature request
about: Suggest an idea or report a bug

---

- If you have troubles to run the components, or you'd like to ask a question - please use [PiggyMetrics gitter chat](https://gitter.im/sqshq/PiggyMetrics)

- If you'd like to propose an improvement or report a bug, please provide a clear and concise description, attach logs and screenshots if possible. The issue should be ready to be implemented without any additional questions. PiggyMetrics is open source, nobody maintains it during the work hours. If you'd like the issue to be fixed, please consider to contibute your time to do that.

Thank you.


================================================
FILE: .gitignore
================================================
# Intellij
.idea/
*.iml
*.iws

# Mac
.DS_Store

# Maven
log/
target/

# Eclipse
**/*.project
**/*.classpath
**/*.settings

================================================
FILE: .travis.yml
================================================
dist: trusty
sudo: required

services:
  - docker

language: java
jdk: oraclejdk8

env:
  global:
    - secure: "GeONVsTD48Y88CKoqupo/FC1Gy0eCrT1UNylvMzz5VYcLhWcUcu/d4870ZJznBqslGHbFaRc6VCXFLnbKNyR5Chgg127ouWOv/NFubJ5cO0UjHlBwoAxQ/SIrxG9W4B6Y2VeWRO0SIPHF6wUVeELiaPmIIe/jF15/SWJA926G2dF0+zTbn1KNWoVRi9pxZ0bIbEvVcVfHjWHsPtho916KRZ7ToV27f5E9DPLVMraK2HROOplJlXKNLuUor9xSmtOB/787yNrZmdsUaQDMHVfru9yEubfg4tF5ydoluB+JPzeUqIK2PrDgAiwmkEdoJFfbAOqwdy8vZkgpYd/t5vkhbOn3yA0QO1pnyhidx1YgyoJN3HwfMeVNQwUVg8jw7bltVe/DxsNo/AW11Tu7jKteuxewRHCxORzaUSmy5rnLq3AKIXT6h8Kq5VxP5tGbQypa7/z+Zu4vfOBdKGMiLllQ0vhhU0osgYzk/jT4KknuWQtOkX+QTS9iViIUwQgcn3kIMlz4eO83Mbt+IkNvgjF0DyE64mfV2ThTjXDV6959g3Nl/Fl95VMSTg95xtl0tbf733Lj+9HCIfLetlBz4ZzOqaDgD5fRL5HA8jR3FFHVdMd+dx/JELjSRHxO6ZFrCVG/2hBldIakO31/FbpODnDIkKO+86Oqz9DPKVnLJlmZp4=" # DOCKER_EMAIL
    - secure: "Gl6a03cI88dKHV4rjP1IkYqCdVe7IM0XNcEzFDCxmvXHWSpqlotntOYtgvtRKsYOzb0cfdQwgFuwj80glUbFX5vbX1y5r+qR5sQSrJVi61e8Pijn0MT7rE/d2gCJwaRTkR2lvtRRTIX41LA+aZ6F7+xFSd+ni82IlaXtDywQJWpCEmxcSqSUd5nVhHzH5JZmkYQmQ8fjxzGUhpeePfapYThPxXsHGxmJeoIlEDM1TEFtxVf3Zo9D10812uesa7EwNSKL6MOBU/Me7+liIHdRRpRwVmOjaFAZLeHsUfZQWcLWer0ODULov1U/YMdF860gV1X8PPYxAYNnWqevOGZIsYTX60yem/dCq90Lx7cIiK/TBZIS7x9k65QwP/shnO/RK8PPANBt8bJ4FBxmDPRMPRvgCPp4wQIYTyaiXd0M6BmK+LysS5cRgOOg7YF+ZRqKjNGY9rkNeGs0x8LIaE4Vz138tJCVJ0U+r2OOZFLCIu4dmvuOo1rWf4Hzh+Xt/nx8RrAwwqHKWRyayHkZEbQv2dNGcJsZyAzXsxA6NTDGQfKYloX5oY4qq3BMCkRoid9sLHoJvZrfkN6mjbZkEd2Ed3RzyTIxasmRUeD45vfr7go9ts1a6ppDrRYJWLi26pqyPhimTI0ljEYXp4QnK5JMya2y6H0wo/hJmzrqfXj4+C0=" # DOCKER_USER
    - secure: "VRlJyPOz7fUmtFdpTdO51BVcjKUGP5t7KF5bG7TSJPXsal7SSxjt6desLQ6zv31tKBp/SrgbnH4hloeAe38hL1I5gQKLPuNjOYhtolgLHlCO3aJiJ0vn0o6mgxOok4S/ul6EMy8VLbKzwt7GrruoaDNVadwc98NY+Grr1eLUzD5CVxa4luSahtKASheCtM29OQOj42Ivnc/MUUMYMymYa/zgIkROqI1ZbQK12NGwx13FzjjF2C9WyTR8IMFOeiuL/Ha8wxT2VeYExWkNw8TQKg35WT26axSoI92BBjPHY+l4IDQ0g8N176sAG52gbz4WXx60kRgqHrn+b5cjO/v1PknqXCqwWVrskm/mgGxJ4IVmpqa7ItDYtoVPzW4hyPsEHWyPMjii5280VdqVRueHyxSBH/uF3iQCDwR0hRdVnPPvgrt40/jbiD3pBhnDQErHCu54FA7uzfFT8LUvj3PgHn19KWAb4gKMpP0AZA3aDOD/3+db1x25ozhDXoCLPFk+kK0lp5mwTKka910lX4L25wp2P3RDdbGQTeVjBBp5+IxzfBuF7m2aEww7HgpB/TmHGaxo61cZfLFwcU2tfIQnPVRiomMqh85xFHIkDETNJJMdV1o+Im5maOzg3u5iy7E6dJec6jTYSCIzh6BemM+scYVZzLkYZVRyrUQkUj7ldoI=" # DOCKER_PASS
    - COMMIT=${TRAVIS_COMMIT::7}

after_success:
  - bash <(curl -s https://codecov.io/bash)
  - docker login -u $DOCKER_USER -p $DOCKER_PASS

  #TAG
  - export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH ; fi`

  # CONFIG SERVICE
  - export CONFIG=sqshq/piggymetrics-config
  - docker build -t $CONFIG:$COMMIT ./config
  - docker tag $CONFIG:$COMMIT $CONFIG:$TAG
  - docker push $CONFIG

  # REGISTRY
  - export REGISTRY=sqshq/piggymetrics-registry
  - docker build -t $REGISTRY:$COMMIT ./registry
  - docker tag $REGISTRY:$COMMIT $REGISTRY:$TAG
  - docker push $REGISTRY

  # GATEWAY
  - export GATEWAY=sqshq/piggymetrics-gateway
  - docker build -t $GATEWAY:$COMMIT ./gateway
  - docker tag $GATEWAY:$COMMIT $GATEWAY:$TAG
  - docker push $GATEWAY

  # AUTH SERVICE
  - export AUTH_SERVICE=sqshq/piggymetrics-auth-service
  - docker build -t $AUTH_SERVICE:$COMMIT ./auth-service
  - docker tag $AUTH_SERVICE:$COMMIT $AUTH_SERVICE:$TAG
  - docker push $AUTH_SERVICE

  # ACCOUNT SERVICE
  - export ACCOUNT_SERVICE=sqshq/piggymetrics-account-service
  - docker build -t $ACCOUNT_SERVICE:$COMMIT ./account-service
  - docker tag $ACCOUNT_SERVICE:$COMMIT $ACCOUNT_SERVICE:$TAG
  - docker push $ACCOUNT_SERVICE

  # STATISTICS SERVICE
  - export STATISTICS_SERVICE=sqshq/piggymetrics-statistics-service
  - docker build -t $STATISTICS_SERVICE:$COMMIT ./statistics-service
  - docker tag $STATISTICS_SERVICE:$COMMIT $STATISTICS_SERVICE:$TAG
  - docker push $STATISTICS_SERVICE

  # NOTIFICATION_SERVICE
  - export NOTIFICATION_SERVICE=sqshq/piggymetrics-notification-service
  - docker build -t $NOTIFICATION_SERVICE:$COMMIT ./notification-service
  - docker tag $NOTIFICATION_SERVICE:$COMMIT $NOTIFICATION_SERVICE:$TAG
  - docker push $NOTIFICATION_SERVICE

  # MONITORING
  - export MONITORING=sqshq/piggymetrics-monitoring
  - docker build -t $MONITORING:$COMMIT ./monitoring
  - docker tag $MONITORING:$COMMIT $MONITORING:$TAG
  - docker push $MONITORING

  # TURBINE STREAM SERVICE
  - export TURBINE=sqshq/piggymetrics-turbine-stream-service
  - docker build -t $TURBINE:$COMMIT ./turbine-stream-service
  - docker tag $TURBINE:$COMMIT $TURBINE:$TAG
  - docker push $TURBINE

  # MONGO DB
  - export MONGO_DB=sqshq/piggymetrics-mongodb
  - docker build -t $MONGO_DB:$COMMIT ./mongodb
  - docker tag $MONGO_DB:$COMMIT $MONGO_DB:$TAG
  - docker push $MONGO_DB


================================================
FILE: LICENCE
================================================
The MIT License (MIT)

Copyright (c) 2016 Alexander Lukyanchikov, http://sqshq.com

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

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

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


================================================
FILE: README.md
================================================
[![Build Status](https://travis-ci.org/sqshq/PiggyMetrics.svg?branch=master)](https://travis-ci.org/sqshq/PiggyMetrics)
[![codecov.io](https://codecov.io/github/sqshq/PiggyMetrics/coverage.svg?branch=master)](https://codecov.io/github/sqshq/PiggyMetrics?branch=master)
[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/sqshq/PiggyMetrics/blob/master/LICENCE)
[![Join the chat at https://gitter.im/sqshq/PiggyMetrics](https://badges.gitter.im/sqshq/PiggyMetrics.svg)](https://gitter.im/sqshq/PiggyMetrics?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

# Piggy Metrics

Piggy Metrics is a simple financial advisor app built to demonstrate the [Microservice Architecture Pattern](http://martinfowler.com/microservices/) using Spring Boot, Spring Cloud and Docker. The project is intended as a tutorial, but you are welcome to fork it and turn it into something else!

<br>

![](https://cloud.githubusercontent.com/assets/6069066/13864234/442d6faa-ecb9-11e5-9929-34a9539acde0.png)
![Piggy Metrics](https://cloud.githubusercontent.com/assets/6069066/13830155/572e7552-ebe4-11e5-918f-637a49dff9a2.gif)

## Functional services

Piggy Metrics is decomposed into three core microservices. All of them are independently deployable applications organized around certain business domains.

<img width="880" alt="Functional services" src="https://cloud.githubusercontent.com/assets/6069066/13900465/730f2922-ee20-11e5-8df0-e7b51c668847.png">

#### Account service
Contains general input logic and validation: incomes/expenses items, savings and account settings.

Method	| Path	| Description	| User authenticated	| Available from UI
------------- | ------------------------- | ------------- |:-------------:|:----------------:|
GET	| /accounts/{account}	| Get specified account data	|  | 	
GET	| /accounts/current	| Get current account data	| × | ×
GET	| /accounts/demo	| Get demo account data (pre-filled incomes/expenses items, etc)	|   | 	×
PUT	| /accounts/current	| Save current account data	| × | ×
POST	| /accounts/	| Register new account	|   | ×


#### Statistics service
Performs calculations on major statistics parameters and captures time series for each account. Datapoint contains values normalized to base currency and time period. This data is used to track cash flow dynamics during the account lifetime.

Method	| Path	| Description	| User authenticated	| Available from UI
------------- | ------------------------- | ------------- |:-------------:|:----------------:|
GET	| /statistics/{account}	| Get specified account statistics	          |  | 	
GET	| /statistics/current	| Get current account statistics	| × | × 
GET	| /statistics/demo	| Get demo account statistics	|   | × 
PUT	| /statistics/{account}	| Create or update time series datapoint for specified account	|   | 


#### Notification service
Stores user contact information and notification settings (reminders, backup frequency etc). Scheduled worker collects required information from other services and sends e-mail messages to subscribed customers.

Method	| Path	| Description	| User authenticated	| Available from UI
------------- | ------------------------- | ------------- |:-------------:|:----------------:|
GET	| /notifications/settings/current	| Get current account notification settings	| × | ×	
PUT	| /notifications/settings/current	| Save current account notification settings	| × | ×

#### Notes
- Each microservice has its own database, so there is no way to bypass API and access persistence data directly.
- MongoDB is used as a primary database for each of the services.
- All services are talking to each other via the Rest API

## Infrastructure
[Spring cloud](https://spring.io/projects/spring-cloud) provides powerful tools for developers to quickly implement common distributed systems patterns -
<img width="880" alt="Infrastructure services" src="https://cloud.githubusercontent.com/assets/6069066/13906840/365c0d94-eefa-11e5-90ad-9d74804ca412.png">
### Config service
[Spring Cloud Config](http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html) is horizontally scalable centralized configuration service for the distributed systems. It uses a pluggable repository layer that currently supports local storage, Git, and Subversion.

In this project, we are going to use `native profile`, which simply loads config files from the local classpath. You can see `shared` directory in [Config service resources](https://github.com/sqshq/PiggyMetrics/tree/master/config/src/main/resources). Now, when Notification-service requests its configuration, Config service responses with `shared/notification-service.yml` and `shared/application.yml` (which is shared between all client applications).

##### Client side usage
Just build Spring Boot application with `spring-cloud-starter-config` dependency, autoconfiguration will do the rest.

Now you don't need any embedded properties in your application. Just provide `bootstrap.yml` with application name and Config service url:
```yml
spring:
  application:
    name: notification-service
  cloud:
    config:
      uri: http://config:8888
      fail-fast: true
```

##### With Spring Cloud Config, you can change application config dynamically. 
For example, [EmailService bean](https://github.com/sqshq/PiggyMetrics/blob/master/notification-service/src/main/java/com/piggymetrics/notification/service/EmailServiceImpl.java) is annotated with `@RefreshScope`. That means you can change e-mail text and subject without rebuild and restart the Notification service.

First, change required properties in Config server. Then make a refresh call to the Notification service:
`curl -H "Authorization: Bearer #token#" -XPOST http://127.0.0.1:8000/notifications/refresh`

You could also use Repository [webhooks to automate this process](http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html#_push_notifications_and_spring_cloud_bus)

##### Notes
- `@RefreshScope` doesn't work with `@Configuration` classes and doesn't ignores `@Scheduled` methods
- `fail-fast` property means that Spring Boot application will fail startup immediately, if it cannot connect to the Config Service.

### Auth service
Authorization responsibilities are extracted to a separate server, which grants [OAuth2 tokens](https://tools.ietf.org/html/rfc6749) for the backend resource services. Auth Server is used for user authorization as well as for secure machine-to-machine communication inside the perimeter.

In this project, I use [`Password credentials`](https://tools.ietf.org/html/rfc6749#section-4.3) grant type for users authorization (since it's used only by the UI) and [`Client Credentials`](https://tools.ietf.org/html/rfc6749#section-4.4) grant for service-to-service communciation.

Spring Cloud Security provides convenient annotations and autoconfiguration to make this really easy to implement on both server and client side. You can learn more about that in [documentation](http://cloud.spring.io/spring-cloud-security/spring-cloud-security.html).

On the client side, everything works exactly the same as with traditional session-based authorization. You can retrieve `Principal` object from the request, check user roles using the expression-based access control and `@PreAuthorize` annotation.

Each PiggyMetrics client has a scope: `server` for backend services and `ui` - for the browser. We can use `@PreAuthorize` annotation to protect controllers from  an external access:

``` java
@PreAuthorize("#oauth2.hasScope('server')")
@RequestMapping(value = "accounts/{name}", method = RequestMethod.GET)
public List<DataPoint> getStatisticsByAccountName(@PathVariable String name) {
	return statisticsService.findByAccountName(name);
}
```

### API Gateway
API Gateway is a single entry point into the system, used to handle requests and routing them to the appropriate backend service or by [aggregating results from a scatter-gather call](http://techblog.netflix.com/2013/01/optimizing-netflix-api.html). Also, it can be used for authentication, insights, stress and canary testing, service migration, static response handling and active traffic management.

Netflix opensourced [such an edge service](http://techblog.netflix.com/2013/06/announcing-zuul-edge-service-in-cloud.html) and Spring Cloud allows to use it with a single `@EnableZuulProxy` annotation. In this project, we use Zuul to store some static content (the UI application) and to route requests to appropriate the microservices. Here's a simple prefix-based routing configuration for the Notification service:

```yml
zuul:
  routes:
    notification-service:
        path: /notifications/**
        serviceId: notification-service
        stripPrefix: false

```

That means all requests starting with `/notifications` will be routed to the Notification service. There is no hardcoded addresses, as you can see. Zuul uses [Service discovery](https://github.com/sqshq/PiggyMetrics/blob/master/README.md#service-discovery) mechanism to locate Notification service instances and also [Circuit Breaker and Load Balancer](https://github.com/sqshq/PiggyMetrics/blob/master/README.md#http-client-load-balancer-and-circuit-breaker), described below.

### Service Discovery

Service Discovery allows automatic detection of the network locations for all registered services. These locations might have dynamically assigned addresses due to auto-scaling, failures or upgrades.

The key part of Service discovery is the Registry. In this project, we use Netflix Eureka. Eureka is a good example of the client-side discovery pattern, where client is responsible for looking up the locations of available service instances and load balancing between them.

With Spring Boot, you can easily build Eureka Registry using the `spring-cloud-starter-eureka-server` dependency, `@EnableEurekaServer` annotation and simple configuration properties.

Client support enabled with `@EnableDiscoveryClient` annotation a `bootstrap.yml` with application name:
``` yml
spring:
  application:
    name: notification-service
```

This service will be registered with the Eureka Server and provided with metadata such as host, port, health indicator URL, home page etc. Eureka receives heartbeat messages from each instance belonging to the service. If the heartbeat fails over a configurable timetable, the instance will be removed from the registry.

Also, Eureka provides a simple interface where you can track running services and a number of available instances: `http://localhost:8761`

### Load balancer, Circuit breaker and Http client

#### Ribbon
Ribbon is a client side load balancer which gives you a lot of control over the behaviour of HTTP and TCP clients. Compared to a traditional load balancer, there is no need in additional network hop - you can contact desired service directly.

Out of the box, it natively integrates with Spring Cloud and Service Discovery. [Eureka Client](https://github.com/sqshq/PiggyMetrics#service-discovery) provides a dynamic list of available servers so Ribbon could balance between them.

#### Hystrix
Hystrix is the implementation of [Circuit Breaker Pattern](http://martinfowler.com/bliki/CircuitBreaker.html), which gives us a control over latency and network failures while communicating with other services. The main idea is to stop cascading failures in the distributed environment - that helps to fail fast and recover as soon as possible - important aspects of a fault-tolerant system that can self-heal.

Moreover, Hystrix generates metrics on execution outcomes and latency for each command, that we can use to [monitor system's behavior](https://github.com/sqshq/PiggyMetrics#monitor-dashboard).

#### Feign
Feign is a declarative Http client which seamlessly integrates with Ribbon and Hystrix. Actually, a single `spring-cloud-starter-feign` dependency and `@EnableFeignClients` annotation gives us a full set of tools, including Load balancer, Circuit Breaker and Http client with reasonable default configuration.

Here is an example from the Account Service:

``` java
@FeignClient(name = "statistics-service")
public interface StatisticsServiceClient {

	@RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
	void updateStatistics(@PathVariable("accountName") String accountName, Account account);

}
```

- Everything you need is just an interface
- You can share `@RequestMapping` part between Spring MVC controller and Feign methods
- Above example specifies just a desired service id - `statistics-service`, thanks to auto-discovery through Eureka

### Monitor dashboard

In this project configuration, each microservice with Hystrix on board pushes metrics to Turbine via Spring Cloud Bus (with AMQP broker). The Monitoring project is just a small Spring boot application with the [Turbine](https://github.com/Netflix/Turbine) and [Hystrix Dashboard](https://github.com/Netflix-Skunkworks/hystrix-dashboard).

Let's see observe the behavior of our system under load: Statistics Service imitates a delay during the request processing. The response timeout is set to 1 second:

<img width="880" src="https://cloud.githubusercontent.com/assets/6069066/14194375/d9a2dd80-f7be-11e5-8bcc-9a2fce753cfe.png">

<img width="212" src="https://cloud.githubusercontent.com/assets/6069066/14127349/21e90026-f628-11e5-83f1-60108cb33490.gif">	| <img width="212" src="https://cloud.githubusercontent.com/assets/6069066/14127348/21e6ed40-f628-11e5-9fa4-ed527bf35129.gif"> | <img width="212" src="https://cloud.githubusercontent.com/assets/6069066/14127346/21b9aaa6-f628-11e5-9bba-aaccab60fd69.gif"> | <img width="212" src="https://cloud.githubusercontent.com/assets/6069066/14127350/21eafe1c-f628-11e5-8ccd-a6b6873c046a.gif">
--- |--- |--- |--- |
| `0 ms delay` | `500 ms delay` | `800 ms delay` | `1100 ms delay`
| Well behaving system. Throughput is about 22 rps. Small number of active threads in the Statistics service. Median service time is about 50 ms. | The number of active threads is growing. We can see purple number of thread-pool rejections and therefore about 40% of errors, but the circuit is still closed. | Half-open state: the ratio of failed commands is higher than 50%, so the circuit breaker kicks in. After sleep window amount of time, the next request goes through. | 100 percent of the requests fail. The circuit is now permanently open. Retry after sleep time won't close the circuit again because a single request is too slow.

### Log analysis

Centralized logging can be very useful while attempting to identify problems in a distributed environment. Elasticsearch, Logstash and Kibana stack lets you search and analyze your logs, utilization and network activity data with ease.

### Distributed tracing

Analyzing problems in distributed systems can be difficult, especially trying to trace requests that propagate from one microservice to another.

[Spring Cloud Sleuth](https://cloud.spring.io/spring-cloud-sleuth/) solves this problem by providing support for the distributed tracing. It adds two types of IDs to the logging: `traceId` and `spanId`. `spanId` represents a basic unit of work, for example sending an HTTP request. The traceId contains a set of spans forming a tree-like structure. For example, with a distributed big-data store, a trace might be formed by a PUT request. Using `traceId` and `spanId` for each operation we know when and where our application is as it processes a request, making reading logs much easier. 

The logs are as follows, notice the `[appname,traceId,spanId,exportable]` entries from the Slf4J MDC:

```text
2018-07-26 23:13:49.381  WARN [gateway,3216d0de1384bb4f,3216d0de1384bb4f,false] 2999 --- [nio-4000-exec-1] o.s.c.n.z.f.r.s.AbstractRibbonCommand    : The Hystrix timeout of 20000ms for the command account-service is set lower than the combination of the Ribbon read and connect timeout, 80000ms.
2018-07-26 23:13:49.562  INFO [account-service,3216d0de1384bb4f,404ff09c5cf91d2e,false] 3079 --- [nio-6000-exec-1] c.p.account.service.AccountServiceImpl   : new account has been created: test
```

- *`appname`*: The name of the application that logged the span from the property `spring.application.name`
- *`traceId`*: This is an ID that is assigned to a single request, job, or action
- *`spanId`*: The ID of a specific operation that took place
- *`exportable`*: Whether the log should be exported to [Zipkin](https://zipkin.io/)

## Infrastructure automation

Deploying microservices, with their interdependence, is much more complex process than deploying a monolithic application. It is really important to have a fully automated infrastructure. We can achieve following benefits with Continuous Delivery approach:

- The ability to release software anytime
- Any build could end up being a release
- Build artifacts once - deploy as needed

Here is a simple Continuous Delivery workflow, implemented in this project:

<img width="880" src="https://cloud.githubusercontent.com/assets/6069066/14159789/0dd7a7ce-f6e9-11e5-9fbb-a7fe0f4431e3.png">

In this [configuration](https://github.com/sqshq/PiggyMetrics/blob/master/.travis.yml), Travis CI builds tagged images for each successful git push. So, there are always the `latest` images for each microservice on [Docker Hub](https://hub.docker.com/r/sqshq/) and older images, tagged with git commit hash. It's easy to deploy any of them and quickly rollback, if needed.

## Let's try it out

Note that starting 8 Spring Boot applications, 4 MongoDB instances and a RabbitMq requires at least 4Gb of RAM.

#### Before you start
- Install Docker and Docker Compose.
- Change environment variable values in `.env` file for more security or leave it as it is.
- Build the project: `mvn package [-DskipTests]`

#### Production mode
In this mode, all latest images will be pulled from Docker Hub.
Just copy `docker-compose.yml` and hit `docker-compose up`

#### Development mode
If you'd like to build images yourself, you have to clone the repository and build artifacts using maven. After that, run `docker-compose -f docker-compose.yml -f docker-compose.dev.yml up`

`docker-compose.dev.yml` inherits `docker-compose.yml` with additional possibility to build images locally and expose all containers ports for convenient development.

If you'd like to start applications in Intellij Idea you need to either use [EnvFile plugin](https://plugins.jetbrains.com/plugin/7861-envfile) or manually export environment variables listed in `.env` file (make sure they were exported: `printenv`)

#### Important endpoints
- http://localhost:80 - Gateway
- http://localhost:8761 - Eureka Dashboard
- http://localhost:9000/hystrix - Hystrix Dashboard (Turbine stream link: `http://turbine-stream-service:8080/turbine/turbine.stream`)
- http://localhost:15672 - RabbitMq management (default login/password: guest/guest)

## Contributions are welcome!

PiggyMetrics is open source, and would greatly appreciate your help. Feel free to suggest and implement any improvements.


================================================
FILE: account-service/Dockerfile
================================================
FROM java:8-jre
MAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>

ADD ./target/account-service.jar /app/
CMD ["java", "-Xmx200m", "-jar", "/app/account-service.jar"]

EXPOSE 6000

================================================
FILE: account-service/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<artifactId>account-service</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>account-service</name>

	<parent>
		<groupId>com.piggymetrics</groupId>
		<artifactId>piggymetrics</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-oauth2</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-sleuth</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-bus-amqp</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-netflix-hystrix-stream</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>de.flapdoodle.embed</groupId>
			<artifactId>de.flapdoodle.embed.mongo</artifactId>
			<version>1.50.3</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.jayway.jsonpath</groupId>
			<artifactId>json-path</artifactId>
			<version>2.2.0</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<finalName>account-service</finalName>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.jacoco</groupId>
				<artifactId>jacoco-maven-plugin</artifactId>
				<version>0.7.6.201602180812</version>
				<executions>
					<execution>
						<goals>
							<goal>prepare-agent</goal>
						</goals>
					</execution>
					<execution>
						<id>report</id>
						<phase>test</phase>
						<goals>
							<goal>report</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

</project>


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/AccountApplication.java
================================================
package com.piggymetrics.account;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;

@SpringBootApplication
@EnableDiscoveryClient
@EnableOAuth2Client
@EnableFeignClients
@EnableCircuitBreaker
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AccountApplication {

	public static void main(String[] args) {
		SpringApplication.run(AccountApplication.class, args);
	}

}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/client/AuthServiceClient.java
================================================
package com.piggymetrics.account.client;

import com.piggymetrics.account.domain.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient(name = "auth-service")
public interface AuthServiceClient {

	@RequestMapping(method = RequestMethod.POST, value = "/uaa/users", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
	void createUser(User user);

}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/client/StatisticsServiceClient.java
================================================
package com.piggymetrics.account.client;

import com.piggymetrics.account.domain.Account;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient(name = "statistics-service", fallback = StatisticsServiceClientFallback.class)
public interface StatisticsServiceClient {

	@RequestMapping(method = RequestMethod.PUT, value = "/statistics/{accountName}", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
	void updateStatistics(@PathVariable("accountName") String accountName, Account account);

}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/client/StatisticsServiceClientFallback.java
================================================
package com.piggymetrics.account.client;

import com.piggymetrics.account.domain.Account;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @author cdov
 */
@Component
public class StatisticsServiceClientFallback implements StatisticsServiceClient {
    private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsServiceClientFallback.class);
    @Override
    public void updateStatistics(String accountName, Account account) {
        LOGGER.error("Error during update statistics for account: {}", accountName);
    }
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/config/ResourceServerConfig.java
================================================
package com.piggymetrics.account.config;

import com.piggymetrics.account.service.security.CustomUserInfoTokenServices;
import feign.RequestInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;

/**
 * @author cdov
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private final ResourceServerProperties sso;

    @Autowired
    public ResourceServerConfig(ResourceServerProperties sso) {
        this.sso = sso;
    }

    @Bean
    @ConfigurationProperties(prefix = "security.oauth2.client")
    public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {
        return new ClientCredentialsResourceDetails();
    }

    @Bean
    public RequestInterceptor oauth2FeignRequestInterceptor(){
        return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), clientCredentialsResourceDetails());
    }

    @Bean
    public OAuth2RestTemplate clientCredentialsRestTemplate() {
        return new OAuth2RestTemplate(clientCredentialsResourceDetails());
    }

    @Bean
    public ResourceServerTokenServices tokenServices() {
        return new CustomUserInfoTokenServices(sso.getUserInfoUri(), sso.getClientId());
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/" , "/demo").permitAll()
                .anyRequest().authenticated();
    }
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/controller/AccountController.java
================================================
package com.piggymetrics.account.controller;

import com.piggymetrics.account.domain.Account;
import com.piggymetrics.account.domain.User;
import com.piggymetrics.account.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.security.Principal;

@RestController
public class AccountController {

	@Autowired
	private AccountService accountService;

	@PreAuthorize("#oauth2.hasScope('server') or #name.equals('demo')")
	@RequestMapping(path = "/{name}", method = RequestMethod.GET)
	public Account getAccountByName(@PathVariable String name) {
		return accountService.findByName(name);
	}

	@RequestMapping(path = "/current", method = RequestMethod.GET)
	public Account getCurrentAccount(Principal principal) {
		return accountService.findByName(principal.getName());
	}

	@RequestMapping(path = "/current", method = RequestMethod.PUT)
	public void saveCurrentAccount(Principal principal, @Valid @RequestBody Account account) {
		accountService.saveChanges(principal.getName(), account);
	}

	@RequestMapping(path = "/", method = RequestMethod.POST)
	public Account createNewAccount(@Valid @RequestBody User user) {
		return accountService.create(user);
	}
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/controller/ErrorHandler.java
================================================
package com.piggymetrics.account.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;

@ControllerAdvice
public class ErrorHandler {

	private final Logger log = LoggerFactory.getLogger(getClass());

	// TODO add MethodArgumentNotValidException handler
	// TODO remove such general handler
	@ExceptionHandler(IllegalArgumentException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public void processValidationError(IllegalArgumentException e) {
		log.info("Returning HTTP 400 Bad Request", e);
	}
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/domain/Account.java
================================================
package com.piggymetrics.account.domain;

import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.hibernate.validator.constraints.Length;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;

@Document(collection = "accounts")
@JsonIgnoreProperties(ignoreUnknown = true)
public class Account {

	@Id
	private String name;

	private Date lastSeen;

	@Valid
	private List<Item> incomes;

	@Valid
	private List<Item> expenses;

	@Valid
	@NotNull
	private Saving saving;

	@Length(min = 0, max = 20_000)
	private String note;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getLastSeen() {
		return lastSeen;
	}

	public void setLastSeen(Date lastSeen) {
		this.lastSeen = lastSeen;
	}

	public List<Item> getIncomes() {
		return incomes;
	}

	public void setIncomes(List<Item> incomes) {
		this.incomes = incomes;
	}

	public List<Item> getExpenses() {
		return expenses;
	}

	public void setExpenses(List<Item> expenses) {
		this.expenses = expenses;
	}

	public Saving getSaving() {
		return saving;
	}

	public void setSaving(Saving saving) {
		this.saving = saving;
	}

	public String getNote() {
		return note;
	}

	public void setNote(String note) {
		this.note = note;
	}
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/domain/Currency.java
================================================
package com.piggymetrics.account.domain;

public enum Currency {

	USD, EUR, RUB;

	public static Currency getDefault() {
		return USD;
	}
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/domain/Item.java
================================================
package com.piggymetrics.account.domain;

import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;

public class Item {

	@NotNull
	@Length(min = 1, max = 20)
	private String title;

	@NotNull
	private BigDecimal amount;

	@NotNull
	private Currency currency;

	@NotNull
	private TimePeriod period;

	@NotNull
	private String icon;

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public BigDecimal getAmount() {
		return amount;
	}

	public void setAmount(BigDecimal amount) {
		this.amount = amount;
	}

	public Currency getCurrency() {
		return currency;
	}

	public void setCurrency(Currency currency) {
		this.currency = currency;
	}

	public TimePeriod getPeriod() {
		return period;
	}

	public void setPeriod(TimePeriod period) {
		this.period = period;
	}

	public String getIcon() {
		return icon;
	}

	public void setIcon(String icon) {
		this.icon = icon;
	}
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/domain/Saving.java
================================================
package com.piggymetrics.account.domain;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;

public class Saving {

	@NotNull
	private BigDecimal amount;

	@NotNull
	private Currency currency;

	@NotNull
	private BigDecimal interest;

	@NotNull
	private Boolean deposit;

	@NotNull
	private Boolean capitalization;

	public BigDecimal getAmount() {
		return amount;
	}

	public void setAmount(BigDecimal amount) {
		this.amount = amount;
	}

	public Currency getCurrency() {
		return currency;
	}

	public void setCurrency(Currency currency) {
		this.currency = currency;
	}

	public BigDecimal getInterest() {
		return interest;
	}

	public void setInterest(BigDecimal interest) {
		this.interest = interest;
	}

	public Boolean getDeposit() {
		return deposit;
	}

	public void setDeposit(Boolean deposit) {
		this.deposit = deposit;
	}

	public Boolean getCapitalization() {
		return capitalization;
	}

	public void setCapitalization(Boolean capitalization) {
		this.capitalization = capitalization;
	}
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/domain/TimePeriod.java
================================================
package com.piggymetrics.account.domain;

public enum TimePeriod {

	YEAR, QUARTER, MONTH, DAY, HOUR

}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/domain/User.java
================================================
package com.piggymetrics.account.domain;

import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotNull;

public class User {

	@NotNull
	@Length(min = 3, max = 20)
	private String username;

	@NotNull
	@Length(min = 6, max = 40)
	private String password;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/repository/AccountRepository.java
================================================
package com.piggymetrics.account.repository;

import com.piggymetrics.account.domain.Account;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AccountRepository extends CrudRepository<Account, String> {

	Account findByName(String name);

}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/service/AccountService.java
================================================
package com.piggymetrics.account.service;

import com.piggymetrics.account.domain.Account;
import com.piggymetrics.account.domain.User;

public interface AccountService {

	/**
	 * Finds account by given name
	 *
	 * @param accountName
	 * @return found account
	 */
	Account findByName(String accountName);

	/**
	 * Checks if account with the same name already exists
	 * Invokes Auth Service user creation
	 * Creates new account with default parameters
	 *
	 * @param user
	 * @return created account
	 */
	Account create(User user);

	/**
	 * Validates and applies incoming account updates
	 * Invokes Statistics Service update
	 *
	 * @param name
	 * @param update
	 */
	void saveChanges(String name, Account update);
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/service/AccountServiceImpl.java
================================================
package com.piggymetrics.account.service;

import com.piggymetrics.account.client.AuthServiceClient;
import com.piggymetrics.account.client.StatisticsServiceClient;
import com.piggymetrics.account.domain.Account;
import com.piggymetrics.account.domain.Currency;
import com.piggymetrics.account.domain.Saving;
import com.piggymetrics.account.domain.User;
import com.piggymetrics.account.repository.AccountRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Date;

@Service
public class AccountServiceImpl implements AccountService {

	private final Logger log = LoggerFactory.getLogger(getClass());

	@Autowired
	private StatisticsServiceClient statisticsClient;

	@Autowired
	private AuthServiceClient authClient;

	@Autowired
	private AccountRepository repository;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Account findByName(String accountName) {
		Assert.hasLength(accountName);
		return repository.findByName(accountName);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Account create(User user) {

		Account existing = repository.findByName(user.getUsername());
		Assert.isNull(existing, "account already exists: " + user.getUsername());

		authClient.createUser(user);

		Saving saving = new Saving();
		saving.setAmount(new BigDecimal(0));
		saving.setCurrency(Currency.getDefault());
		saving.setInterest(new BigDecimal(0));
		saving.setDeposit(false);
		saving.setCapitalization(false);

		Account account = new Account();
		account.setName(user.getUsername());
		account.setLastSeen(new Date());
		account.setSaving(saving);

		repository.save(account);

		log.info("new account has been created: " + account.getName());

		return account;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void saveChanges(String name, Account update) {

		Account account = repository.findByName(name);
		Assert.notNull(account, "can't find account with name " + name);

		account.setIncomes(update.getIncomes());
		account.setExpenses(update.getExpenses());
		account.setSaving(update.getSaving());
		account.setNote(update.getNote());
		account.setLastSeen(new Date());
		repository.save(account);

		log.debug("account {} changes has been saved", name);

		statisticsClient.updateStatistics(name, account);
	}
}


================================================
FILE: account-service/src/main/java/com/piggymetrics/account/service/security/CustomUserInfoTokenServices.java
================================================
package com.piggymetrics.account.service.security;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor;
import org.springframework.boot.autoconfigure.security.oauth2.resource.FixedAuthoritiesExtractor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;

import java.util.*;

/**
 * Extended implementation of {@link org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices}
 *
 * By default, it designed to return only user details. This class provides {@link #getRequest(Map)} method, which
 * returns clientId and scope of calling service. This information used in controller's security checks.
 */

public class CustomUserInfoTokenServices implements ResourceServerTokenServices {

	protected final Log logger = LogFactory.getLog(getClass());

	private static final String[] PRINCIPAL_KEYS = new String[] { "user", "username",
			"userid", "user_id", "login", "id", "name" };

	private final String userInfoEndpointUrl;

	private final String clientId;

	private OAuth2RestOperations restTemplate;

	private String tokenType = DefaultOAuth2AccessToken.BEARER_TYPE;

	private AuthoritiesExtractor authoritiesExtractor = new FixedAuthoritiesExtractor();

	public CustomUserInfoTokenServices(String userInfoEndpointUrl, String clientId) {
		this.userInfoEndpointUrl = userInfoEndpointUrl;
		this.clientId = clientId;
	}

	public void setTokenType(String tokenType) {
		this.tokenType = tokenType;
	}

	public void setRestTemplate(OAuth2RestOperations restTemplate) {
		this.restTemplate = restTemplate;
	}

	public void setAuthoritiesExtractor(AuthoritiesExtractor authoritiesExtractor) {
		this.authoritiesExtractor = authoritiesExtractor;
	}

	@Override
	public OAuth2Authentication loadAuthentication(String accessToken)
			throws AuthenticationException, InvalidTokenException {
		Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);
		if (map.containsKey("error")) {
			this.logger.debug("userinfo returned error: " + map.get("error"));
			throw new InvalidTokenException(accessToken);
		}
		return extractAuthentication(map);
	}

	private OAuth2Authentication extractAuthentication(Map<String, Object> map) {
		Object principal = getPrincipal(map);
		OAuth2Request request = getRequest(map);
		List<GrantedAuthority> authorities = this.authoritiesExtractor
				.extractAuthorities(map);
		UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
				principal, "N/A", authorities);
		token.setDetails(map);
		return new OAuth2Authentication(request, token);
	}

	private Object getPrincipal(Map<String, Object> map) {
		for (String key : PRINCIPAL_KEYS) {
			if (map.containsKey(key)) {
				return map.get(key);
			}
		}
		return "unknown";
	}

	@SuppressWarnings({ "unchecked" })
	private OAuth2Request getRequest(Map<String, Object> map) {
		Map<String, Object> request = (Map<String, Object>) map.get("oauth2Request");

		String clientId = (String) request.get("clientId");
		Set<String> scope = new LinkedHashSet<>(request.containsKey("scope") ?
				(Collection<String>) request.get("scope") : Collections.<String>emptySet());

		return new OAuth2Request(null, clientId, null, true, new HashSet<>(scope),
				null, null, null, null);
	}

	@Override
	public OAuth2AccessToken readAccessToken(String accessToken) {
		throw new UnsupportedOperationException("Not supported: read access token");
	}

	@SuppressWarnings({ "unchecked" })
	private Map<String, Object> getMap(String path, String accessToken) {
		this.logger.debug("Getting user info from: " + path);
		try {
			OAuth2RestOperations restTemplate = this.restTemplate;
			if (restTemplate == null) {
				BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
				resource.setClientId(this.clientId);
				restTemplate = new OAuth2RestTemplate(resource);
			}
			OAuth2AccessToken existingToken = restTemplate.getOAuth2ClientContext()
					.getAccessToken();
			if (existingToken == null || !accessToken.equals(existingToken.getValue())) {
				DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(
						accessToken);
				token.setTokenType(this.tokenType);
				restTemplate.getOAuth2ClientContext().setAccessToken(token);
			}
			return restTemplate.getForEntity(path, Map.class).getBody();
		}
		catch (Exception ex) {
			this.logger.info("Could not fetch user details: " + ex.getClass() + ", "
					+ ex.getMessage());
			return Collections.<String, Object>singletonMap("error",
					"Could not fetch user details");
		}
	}
}


================================================
FILE: account-service/src/main/resources/bootstrap.yml
================================================
spring:
  application:
    name: account-service
  cloud:
    config:
      uri: http://config:8888
      fail-fast: true
      password: ${CONFIG_SERVICE_PASSWORD}
      username: user


================================================
FILE: account-service/src/test/java/com/piggymetrics/account/AccountServiceApplicationTests.java
================================================
package com.piggymetrics.account;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class AccountServiceApplicationTests {

	@Test
	public void contextLoads() {

	}

}


================================================
FILE: account-service/src/test/java/com/piggymetrics/account/client/StatisticsServiceClientFallbackTest.java
================================================
package com.piggymetrics.account.client;

import com.piggymetrics.account.domain.Account;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.Matchers.containsString;

/**
 * @author cdov
 */
@RunWith(SpringRunner.class)
@SpringBootTest(properties = {
        "feign.hystrix.enabled=true"
})
public class StatisticsServiceClientFallbackTest {
    @Autowired
    private StatisticsServiceClient statisticsServiceClient;

    @Rule
    public final OutputCapture outputCapture = new OutputCapture();

    @Before
    public void setup() {
        outputCapture.reset();
    }

    @Test
    public void testUpdateStatisticsWithFailFallback(){
        statisticsServiceClient.updateStatistics("test", new Account());

        outputCapture.expect(containsString("Error during update statistics for account: test"));

    }

}



================================================
FILE: account-service/src/test/java/com/piggymetrics/account/controller/AccountControllerTest.java
================================================
package com.piggymetrics.account.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.piggymetrics.account.domain.*;
import com.piggymetrics.account.service.AccountService;
import com.sun.security.auth.UserPrincipal;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import java.math.BigDecimal;
import java.util.Date;

import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@SpringBootTest
public class AccountControllerTest {

	private static final ObjectMapper mapper = new ObjectMapper();

	@InjectMocks
	private AccountController accountController;

	@Mock
	private AccountService accountService;

	private MockMvc mockMvc;

	@Before
	public void setup() {
		initMocks(this);
		this.mockMvc = MockMvcBuilders.standaloneSetup(accountController).build();
	}

	@Test
	public void shouldGetAccountByName() throws Exception {

		final Account account = new Account();
		account.setName("test");

		when(accountService.findByName(account.getName())).thenReturn(account);

		mockMvc.perform(get("/" + account.getName()))
				.andExpect(jsonPath("$.name").value(account.getName()))
				.andExpect(status().isOk());
	}

	@Test
	public void shouldGetCurrentAccount() throws Exception {

		final Account account = new Account();
		account.setName("test");

		when(accountService.findByName(account.getName())).thenReturn(account);

		mockMvc.perform(get("/current").principal(new UserPrincipal(account.getName())))
				.andExpect(jsonPath("$.name").value(account.getName()))
				.andExpect(status().isOk());
	}

	@Test
	public void shouldSaveCurrentAccount() throws Exception {

		Saving saving = new Saving();
		saving.setAmount(new BigDecimal(1500));
		saving.setCurrency(Currency.USD);
		saving.setInterest(new BigDecimal("3.32"));
		saving.setDeposit(true);
		saving.setCapitalization(false);

		Item grocery = new Item();
		grocery.setTitle("Grocery");
		grocery.setAmount(new BigDecimal(10));
		grocery.setCurrency(Currency.USD);
		grocery.setPeriod(TimePeriod.DAY);
		grocery.setIcon("meal");

		Item salary = new Item();
		salary.setTitle("Salary");
		salary.setAmount(new BigDecimal(9100));
		salary.setCurrency(Currency.USD);
		salary.setPeriod(TimePeriod.MONTH);
		salary.setIcon("wallet");

		final Account account = new Account();
		account.setName("test");
		account.setNote("test note");
		account.setLastSeen(new Date());
		account.setSaving(saving);
		account.setExpenses(ImmutableList.of(grocery));
		account.setIncomes(ImmutableList.of(salary));

		String json = mapper.writeValueAsString(account);

		mockMvc.perform(put("/current").principal(new UserPrincipal(account.getName())).contentType(MediaType.APPLICATION_JSON).content(json))
				.andExpect(status().isOk());
	}

	@Test
	public void shouldFailOnValidationTryingToSaveCurrentAccount() throws Exception {

		final Account account = new Account();
		account.setName("test");

		String json = mapper.writeValueAsString(account);

		mockMvc.perform(put("/current").principal(new UserPrincipal(account.getName())).contentType(MediaType.APPLICATION_JSON).content(json))
				.andExpect(status().isBadRequest());
	}

	@Test
	public void shouldRegisterNewAccount() throws Exception {

		final User user = new User();
		user.setUsername("test");
		user.setPassword("password");

		String json = mapper.writeValueAsString(user);
		System.out.println(json);
		mockMvc.perform(post("/").principal(new UserPrincipal("test")).contentType(MediaType.APPLICATION_JSON).content(json))
				.andExpect(status().isOk());
	}

	@Test
	public void shouldFailOnValidationTryingToRegisterNewAccount() throws Exception {

		final User user = new User();
		user.setUsername("t");

		String json = mapper.writeValueAsString(user);

		mockMvc.perform(post("/").principal(new UserPrincipal("test")).contentType(MediaType.APPLICATION_JSON).content(json))
				.andExpect(status().isBadRequest());
	}
}


================================================
FILE: account-service/src/test/java/com/piggymetrics/account/repository/AccountRepositoryTest.java
================================================
package com.piggymetrics.account.repository;

import com.piggymetrics.account.domain.Account;
import com.piggymetrics.account.domain.Currency;
import com.piggymetrics.account.domain.Item;
import com.piggymetrics.account.domain.Saving;
import com.piggymetrics.account.domain.TimePeriod;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;

import static org.junit.Assert.assertEquals;

@RunWith(SpringRunner.class)
@DataMongoTest
public class AccountRepositoryTest {

	@Autowired
	private AccountRepository repository;

	@Test
	public void shouldFindAccountByName() {

		Account stub = getStubAccount();
		repository.save(stub);

		Account found = repository.findByName(stub.getName());
		assertEquals(stub.getLastSeen(), found.getLastSeen());
		assertEquals(stub.getNote(), found.getNote());
		assertEquals(stub.getIncomes().size(), found.getIncomes().size());
		assertEquals(stub.getExpenses().size(), found.getExpenses().size());
	}

	private Account getStubAccount() {

		Saving saving = new Saving();
		saving.setAmount(new BigDecimal(1500));
		saving.setCurrency(Currency.USD);
		saving.setInterest(new BigDecimal("3.32"));
		saving.setDeposit(true);
		saving.setCapitalization(false);

		Item vacation = new Item();
		vacation.setTitle("Vacation");
		vacation.setAmount(new BigDecimal(3400));
		vacation.setCurrency(Currency.EUR);
		vacation.setPeriod(TimePeriod.YEAR);
		vacation.setIcon("tourism");

		Item grocery = new Item();
		grocery.setTitle("Grocery");
		grocery.setAmount(new BigDecimal(10));
		grocery.setCurrency(Currency.USD);
		grocery.setPeriod(TimePeriod.DAY);
		grocery.setIcon("meal");

		Item salary = new Item();
		salary.setTitle("Salary");
		salary.setAmount(new BigDecimal(9100));
		salary.setCurrency(Currency.USD);
		salary.setPeriod(TimePeriod.MONTH);
		salary.setIcon("wallet");

		Account account = new Account();
		account.setName("test");
		account.setNote("test note");
		account.setLastSeen(new Date());
		account.setSaving(saving);
		account.setExpenses(Arrays.asList(grocery, vacation));
		account.setIncomes(Arrays.asList(salary));

		return account;
	}
}


================================================
FILE: account-service/src/test/java/com/piggymetrics/account/service/AccountServiceTest.java
================================================
package com.piggymetrics.account.service;

import com.piggymetrics.account.client.AuthServiceClient;
import com.piggymetrics.account.client.StatisticsServiceClient;
import com.piggymetrics.account.domain.*;
import com.piggymetrics.account.repository.AccountRepository;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import java.math.BigDecimal;
import java.util.Arrays;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;

public class AccountServiceTest {

	@InjectMocks
	private AccountServiceImpl accountService;

	@Mock
	private StatisticsServiceClient statisticsClient;

	@Mock
	private AuthServiceClient authClient;

	@Mock
	private AccountRepository repository;

	@Before
	public void setup() {
		initMocks(this);
	}

	@Test
	public void shouldFindByName() {

		final Account account = new Account();
		account.setName("test");

		when(accountService.findByName(account.getName())).thenReturn(account);
		Account found = accountService.findByName(account.getName());

		assertEquals(account, found);
	}

	@Test(expected = IllegalArgumentException.class)
	public void shouldFailWhenNameIsEmpty() {
		accountService.findByName("");
	}

	@Test
	public void shouldCreateAccountWithGivenUser() {

		User user = new User();
		user.setUsername("test");

		Account account = accountService.create(user);

		assertEquals(user.getUsername(), account.getName());
		assertEquals(0, account.getSaving().getAmount().intValue());
		assertEquals(Currency.getDefault(), account.getSaving().getCurrency());
		assertEquals(0, account.getSaving().getInterest().intValue());
		assertEquals(false, account.getSaving().getDeposit());
		assertEquals(false, account.getSaving().getCapitalization());
		assertNotNull(account.getLastSeen());

		verify(authClient, times(1)).createUser(user);
		verify(repository, times(1)).save(account);
	}

	@Test
	public void shouldSaveChangesWhenUpdatedAccountGiven() {

		Item grocery = new Item();
		grocery.setTitle("Grocery");
		grocery.setAmount(new BigDecimal(10));
		grocery.setCurrency(Currency.USD);
		grocery.setPeriod(TimePeriod.DAY);
		grocery.setIcon("meal");

		Item salary = new Item();
		salary.setTitle("Salary");
		salary.setAmount(new BigDecimal(9100));
		salary.setCurrency(Currency.USD);
		salary.setPeriod(TimePeriod.MONTH);
		salary.setIcon("wallet");

		Saving saving = new Saving();
		saving.setAmount(new BigDecimal(1500));
		saving.setCurrency(Currency.USD);
		saving.setInterest(new BigDecimal("3.32"));
		saving.setDeposit(true);
		saving.setCapitalization(false);

		final Account update = new Account();
		update.setName("test");
		update.setNote("test note");
		update.setIncomes(Arrays.asList(salary));
		update.setExpenses(Arrays.asList(grocery));
		update.setSaving(saving);

		final Account account = new Account();

		when(accountService.findByName("test")).thenReturn(account);
		accountService.saveChanges("test", update);

		assertEquals(update.getNote(), account.getNote());
		assertNotNull(account.getLastSeen());

		assertEquals(update.getSaving().getAmount(), account.getSaving().getAmount());
		assertEquals(update.getSaving().getCurrency(), account.getSaving().getCurrency());
		assertEquals(update.getSaving().getInterest(), account.getSaving().getInterest());
		assertEquals(update.getSaving().getDeposit(), account.getSaving().getDeposit());
		assertEquals(update.getSaving().getCapitalization(), account.getSaving().getCapitalization());

		assertEquals(update.getExpenses().size(), account.getExpenses().size());
		assertEquals(update.getIncomes().size(), account.getIncomes().size());

		assertEquals(update.getExpenses().get(0).getTitle(), account.getExpenses().get(0).getTitle());
		assertEquals(0, update.getExpenses().get(0).getAmount().compareTo(account.getExpenses().get(0).getAmount()));
		assertEquals(update.getExpenses().get(0).getCurrency(), account.getExpenses().get(0).getCurrency());
		assertEquals(update.getExpenses().get(0).getPeriod(), account.getExpenses().get(0).getPeriod());
		assertEquals(update.getExpenses().get(0).getIcon(), account.getExpenses().get(0).getIcon());
		
		assertEquals(update.getIncomes().get(0).getTitle(), account.getIncomes().get(0).getTitle());
		assertEquals(0, update.getIncomes().get(0).getAmount().compareTo(account.getIncomes().get(0).getAmount()));
		assertEquals(update.getIncomes().get(0).getCurrency(), account.getIncomes().get(0).getCurrency());
		assertEquals(update.getIncomes().get(0).getPeriod(), account.getIncomes().get(0).getPeriod());
		assertEquals(update.getIncomes().get(0).getIcon(), account.getIncomes().get(0).getIcon());
		
		verify(repository, times(1)).save(account);
		verify(statisticsClient, times(1)).updateStatistics("test", account);
	}

	@Test(expected = IllegalArgumentException.class)
	public void shouldFailWhenNoAccountsExistedWithGivenName() {
		final Account update = new Account();
		update.setIncomes(Arrays.asList(new Item()));
		update.setExpenses(Arrays.asList(new Item()));

		when(accountService.findByName("test")).thenReturn(null);
		accountService.saveChanges("test", update);
	}
}


================================================
FILE: account-service/src/test/resources/application.yml
================================================
spring:
  data:
    mongodb:
      database: piggymetrics
      port: 0

================================================
FILE: account-service/src/test/resources/bootstrap.yml
================================================
eureka:
  client:
    enabled: false

================================================
FILE: auth-service/Dockerfile
================================================
FROM java:8-jre
MAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>

ADD ./target/auth-service.jar /app/
CMD ["java", "-Xmx200m", "-jar", "/app/auth-service.jar"]

EXPOSE 5000

================================================
FILE: auth-service/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<artifactId>auth-service</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>auth-service</name>

	<parent>
		<groupId>com.piggymetrics</groupId>
		<artifactId>piggymetrics</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-sleuth</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>de.flapdoodle.embed</groupId>
			<artifactId>de.flapdoodle.embed.mongo</artifactId>
			<version>1.50.3</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.jayway.jsonpath</groupId>
			<artifactId>json-path</artifactId>
			<version>2.2.0</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<finalName>auth-service</finalName>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.jacoco</groupId>
				<artifactId>jacoco-maven-plugin</artifactId>
				<version>0.7.6.201602180812</version>
				<executions>
					<execution>
						<goals>
							<goal>prepare-agent</goal>
						</goals>
					</execution>
					<execution>
						<id>report</id>
						<phase>test</phase>
						<goals>
							<goal>report</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>


================================================
FILE: auth-service/src/main/java/com/piggymetrics/auth/AuthApplication.java
================================================
package com.piggymetrics.auth;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;

@SpringBootApplication
@EnableResourceServer
@EnableDiscoveryClient
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthApplication {

	public static void main(String[] args) {
		SpringApplication.run(AuthApplication.class, args);
	}

}


================================================
FILE: auth-service/src/main/java/com/piggymetrics/auth/config/OAuth2AuthorizationConfig.java
================================================
package com.piggymetrics.auth.config;

import com.piggymetrics.auth.service.security.MongoUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

/**
 * @author cdov
 */
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    private TokenStore tokenStore = new InMemoryTokenStore();
    private final String NOOP_PASSWORD_ENCODE = "{noop}";

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    private MongoUserDetailsService userDetailsService;

    @Autowired
    private Environment env;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        // TODO persist clients details

        // @formatter:off
        clients.inMemory()
                .withClient("browser")
                .authorizedGrantTypes("refresh_token", "password")
                .scopes("ui")
                .and()
                .withClient("account-service")
                .secret(env.getProperty("ACCOUNT_SERVICE_PASSWORD"))
                .authorizedGrantTypes("client_credentials", "refresh_token")
                .scopes("server")
                .and()
                .withClient("statistics-service")
                .secret(env.getProperty("STATISTICS_SERVICE_PASSWORD"))
                .authorizedGrantTypes("client_credentials", "refresh_token")
                .scopes("server")
                .and()
                .withClient("notification-service")
                .secret(env.getProperty("NOTIFICATION_SERVICE_PASSWORD"))
                .authorizedGrantTypes("client_credentials", "refresh_token")
                .scopes("server");
        // @formatter:on
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .tokenStore(tokenStore)
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .passwordEncoder(NoOpPasswordEncoder.getInstance());
    }

}


================================================
FILE: auth-service/src/main/java/com/piggymetrics/auth/config/WebSecurityConfig.java
================================================
package com.piggymetrics.auth.config;

import com.piggymetrics.auth.service.security.MongoUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @author cdov
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MongoUserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
                .authorizeRequests().anyRequest().authenticated()
                .and()
                .csrf().disable();
        // @formatter:on
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

================================================
FILE: auth-service/src/main/java/com/piggymetrics/auth/controller/UserController.java
================================================
package com.piggymetrics.auth.controller;

import com.piggymetrics.auth.domain.User;
import com.piggymetrics.auth.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.security.Principal;

@RestController
@RequestMapping("/users")
public class UserController {

	@Autowired
	private UserService userService;

	@RequestMapping(value = "/current", method = RequestMethod.GET)
	public Principal getUser(Principal principal) {
		return principal;
	}

	@PreAuthorize("#oauth2.hasScope('server')")
	@RequestMapping(method = RequestMethod.POST)
	public void createUser(@Valid @RequestBody User user) {
		userService.create(user);
	}
}


================================================
FILE: auth-service/src/main/java/com/piggymetrics/auth/domain/User.java
================================================
package com.piggymetrics.auth.domain;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.List;

@Document(collection = "users")
public class User implements UserDetails {

	@Id
	private String username;

	private String password;

	@Override
	public String getPassword() {
		return password;
	}

	@Override
	public String getUsername() {
		return username;
	}

	@Override
	public List<GrantedAuthority> getAuthorities() {
		return null;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}
}


================================================
FILE: auth-service/src/main/java/com/piggymetrics/auth/repository/UserRepository.java
================================================
package com.piggymetrics.auth.repository;

import com.piggymetrics.auth.domain.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends CrudRepository<User, String> {

}


================================================
FILE: auth-service/src/main/java/com/piggymetrics/auth/service/UserService.java
================================================
package com.piggymetrics.auth.service;

import com.piggymetrics.auth.domain.User;

public interface UserService {

	void create(User user);

}


================================================
FILE: auth-service/src/main/java/com/piggymetrics/auth/service/UserServiceImpl.java
================================================
package com.piggymetrics.auth.service;

import com.piggymetrics.auth.domain.User;
import com.piggymetrics.auth.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Optional;

@Service
public class UserServiceImpl implements UserService {

	private final Logger log = LoggerFactory.getLogger(getClass());

	private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

	@Autowired
	private UserRepository repository;

	@Override
	public void create(User user) {

		Optional<User> existing = repository.findById(user.getUsername());
		existing.ifPresent(it-> {throw new IllegalArgumentException("user already exists: " + it.getUsername());});

		String hash = encoder.encode(user.getPassword());
		user.setPassword(hash);

		repository.save(user);

		log.info("new user has been created: {}", user.getUsername());
	}
}


================================================
FILE: auth-service/src/main/java/com/piggymetrics/auth/service/security/MongoUserDetailsService.java
================================================
package com.piggymetrics.auth.service.security;

import com.piggymetrics.auth.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class MongoUserDetailsService implements UserDetailsService {

	@Autowired
	private UserRepository repository;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

		return repository.findById(username).orElseThrow(()->new UsernameNotFoundException(username));
	}
}


================================================
FILE: auth-service/src/main/resources/bootstrap.yml
================================================
spring:
  application:
    name: auth-service
  cloud:
    config:
      uri: http://config:8888
      fail-fast: true
      password: ${CONFIG_SERVICE_PASSWORD}
      username: user


================================================
FILE: auth-service/src/test/java/com/piggymetrics/auth/AuthServiceApplicationTests.java
================================================
package com.piggymetrics.auth;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class AuthServiceApplicationTests {

	@Test
	public void contextLoads() {
	}

}


================================================
FILE: auth-service/src/test/java/com/piggymetrics/auth/controller/UserControllerTest.java
================================================
package com.piggymetrics.auth.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.piggymetrics.auth.domain.User;
import com.piggymetrics.auth.service.UserService;
import com.sun.security.auth.UserPrincipal;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import static org.mockito.MockitoAnnotations.initMocks;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {

	private static final ObjectMapper mapper = new ObjectMapper();

	@InjectMocks
	private UserController accountController;

	@Mock
	private UserService userService;

	private MockMvc mockMvc;

	@Before
	public void setup() {
		initMocks(this);
		this.mockMvc = MockMvcBuilders.standaloneSetup(accountController).build();
	}

	@Test
	public void shouldCreateNewUser() throws Exception {

		final User user = new User();
		user.setUsername("test");
		user.setPassword("password");

		String json = mapper.writeValueAsString(user);

		mockMvc.perform(post("/users").contentType(MediaType.APPLICATION_JSON).content(json))
				.andExpect(status().isOk());
	}

	@Test
	public void shouldFailWhenUserIsNotValid() throws Exception {

		final User user = new User();
		user.setUsername("t");
		user.setPassword("p");

		mockMvc.perform(post("/users"))
				.andExpect(status().isBadRequest());
	}

	@Test
	public void shouldReturnCurrentUser() throws Exception {
		mockMvc.perform(get("/users/current").principal(new UserPrincipal("test")))
				.andExpect(jsonPath("$.name").value("test"))
				.andExpect(status().isOk());
	}
}


================================================
FILE: auth-service/src/test/java/com/piggymetrics/auth/repository/UserRepositoryTest.java
================================================
package com.piggymetrics.auth.repository;

import com.piggymetrics.auth.domain.User;
import com.piggymetrics.auth.service.security.MongoUserDetailsService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Optional;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

@RunWith(SpringRunner.class)
@DataMongoTest
public class UserRepositoryTest {

	@Autowired
	private UserRepository repository;

	@Test
	public void shouldSaveAndFindUserByName() {

		User user = new User();
		user.setUsername("name");
		user.setPassword("password");
		repository.save(user);

		Optional<User> found = repository.findById(user.getUsername());
		assertTrue(found.isPresent());
		assertEquals(user.getUsername(), found.get().getUsername());
		assertEquals(user.getPassword(), found.get().getPassword());
	}
}


================================================
FILE: auth-service/src/test/java/com/piggymetrics/auth/service/UserServiceTest.java
================================================
package com.piggymetrics.auth.service;

import com.piggymetrics.auth.domain.User;
import com.piggymetrics.auth.repository.UserRepository;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import java.util.Optional;

import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;

public class UserServiceTest {

	@InjectMocks
	private UserServiceImpl userService;

	@Mock
	private UserRepository repository;

	@Before
	public void setup() {
		initMocks(this);
	}

	@Test
	public void shouldCreateUser() {

		User user = new User();
		user.setUsername("name");
		user.setPassword("password");

		userService.create(user);
		verify(repository, times(1)).save(user);
	}

	@Test(expected = IllegalArgumentException.class)
	public void shouldFailWhenUserAlreadyExists() {

		User user = new User();
		user.setUsername("name");
		user.setPassword("password");

		when(repository.findById(user.getUsername())).thenReturn(Optional.of(new User()));
		userService.create(user);
	}
}


================================================
FILE: auth-service/src/test/java/com/piggymetrics/auth/service/security/MongoUserDetailsServiceTest.java
================================================
package com.piggymetrics.auth.service.security;

import com.piggymetrics.auth.domain.User;
import com.piggymetrics.auth.repository.UserRepository;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.Optional;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;

public class MongoUserDetailsServiceTest {

	@InjectMocks
	private MongoUserDetailsService service;

	@Mock
	private UserRepository repository;

	@Before
	public void setup() {
		initMocks(this);
	}

	@Test
	public void shouldLoadByUsernameWhenUserExists() {

		final User user = new User();

		when(repository.findById(any())).thenReturn(Optional.of(user));
		UserDetails loaded = service.loadUserByUsername("name");

		assertEquals(user, loaded);
	}

	@Test(expected = UsernameNotFoundException.class)
	public void shouldFailToLoadByUsernameWhenUserNotExists() {
		service.loadUserByUsername("name");
	}
}

================================================
FILE: auth-service/src/test/resources/application.yml
================================================
spring:
  data:
    mongodb:
      database: piggymetrics
      port: 0

================================================
FILE: auth-service/src/test/resources/bootstrap.yml
================================================
eureka:
  client:
    enabled: false

================================================
FILE: config/Dockerfile
================================================
FROM java:8-jre
MAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>

ADD ./target/config.jar /app/
CMD ["java", "-Xmx200m", "-jar", "/app/config.jar"]

HEALTHCHECK --interval=30s --timeout=30s CMD curl -f http://localhost:8888/actuator/health || exit 1

EXPOSE 8888

================================================
FILE: config/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<artifactId>config</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>config</name>
	<description>Configuration Server</description>

	<parent>
		<groupId>com.piggymetrics</groupId>
		<artifactId>piggymetrics</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-config-server</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<finalName>config</finalName>
				</configuration>
			</plugin>
		</plugins>
	</build>
	
</project>


================================================
FILE: config/src/main/java/com/piggymetrics/config/ConfigApplication.java
================================================
package com.piggymetrics.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {

	public static void main(String[] args) {
		SpringApplication.run(ConfigApplication.class, args);
	}
}


================================================
FILE: config/src/main/java/com/piggymetrics/config/SecurityConfig.java
================================================
package com.piggymetrics.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @author cdov
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http
            .authorizeRequests()
                .antMatchers("/actuator/**").permitAll()
                .anyRequest().authenticated()
            .and()
                .httpBasic()
                ;
    }
}


================================================
FILE: config/src/main/resources/application.yml
================================================
spring:
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/shared
  profiles:
     active: native
  security:
    user:
      password: ${CONFIG_SERVICE_PASSWORD}

server:
  port: 8888



================================================
FILE: config/src/main/resources/shared/account-service.yml
================================================
security:
  oauth2:
    client:
      clientId: account-service
      clientSecret: ${ACCOUNT_SERVICE_PASSWORD}
      accessTokenUri: http://auth-service:5000/uaa/oauth/token
      grant-type: client_credentials
      scope: server

spring:
  data:
    mongodb:
      host: account-mongodb
      username: user
      password: ${MONGODB_PASSWORD}
      database: piggymetrics
      port: 27017

server:
  servlet:
    context-path: /accounts
  port: 6000

feign:
  hystrix:
    enabled: true

================================================
FILE: config/src/main/resources/shared/application.yml
================================================
logging:
  level:
    org.springframework.security: INFO

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 10000

eureka:
  instance:
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://registry:8761/eureka/

security:
  oauth2:
    resource:
      user-info-uri: http://auth-service:5000/uaa/users/current

spring:
  rabbitmq:
    host: rabbitmq

================================================
FILE: config/src/main/resources/shared/auth-service.yml
================================================
spring:
  data:
    mongodb:
      host: auth-mongodb
      username: user
      password: ${MONGODB_PASSWORD}
      database: piggymetrics
      port: 27017

server:
  servlet:
    context-path: /uaa
  port: 5000


================================================
FILE: config/src/main/resources/shared/gateway.yml
================================================
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 20000

ribbon:
  ReadTimeout: 20000
  ConnectTimeout: 20000

zuul:
  ignoredServices: '*'
  host:
    connect-timeout-millis: 20000
    socket-timeout-millis: 20000

  routes:
    auth-service:
        path: /uaa/**
        url: http://auth-service:5000
        stripPrefix: false
        sensitiveHeaders:

    account-service:
        path: /accounts/**
        serviceId: account-service
        stripPrefix: false
        sensitiveHeaders:

    statistics-service:
        path: /statistics/**
        serviceId: statistics-service
        stripPrefix: false
        sensitiveHeaders:

    notification-service:
        path: /notifications/**
        serviceId: notification-service
        stripPrefix: false
        sensitiveHeaders:

server:
  port: 4000


================================================
FILE: config/src/main/resources/shared/monitoring.yml
================================================


================================================
FILE: config/src/main/resources/shared/notification-service.yml
================================================
security:
  oauth2:
    client:
      clientId: notification-service
      clientSecret: ${NOTIFICATION_SERVICE_PASSWORD}
      accessTokenUri: http://auth-service:5000/uaa/oauth/token
      grant-type: client_credentials
      scope: server

server:
  servlet:
    context-path: /notifications
  port: 8000

remind:
  cron: 0 0 0 * * *
  email:
    text: "Hey, {0}! We''ve missed you here on PiggyMetrics. It''s time to check your budget statistics.\r\n\r\nCheers,\r\nPiggyMetrics team"
    subject: PiggyMetrics reminder

backup:
  cron: 0 0 12 * * *
  email:
    text: "Howdy, {0}. Your account backup is ready.\r\n\r\nCheers,\r\nPiggyMetrics team"
    subject: PiggyMetrics account backup
    attachment: backup.json

spring:
  data:
    mongodb:
      host: notification-mongodb
      username: user
      password: ${MONGODB_PASSWORD}
      database: piggymetrics
      port: 27017
  mail:
    host: smtp.gmail.com
    port: 465
    username: dev-user
    password: dev-password
    properties:
      mail:
        smtp:
          auth: true
          socketFactory:
            port: 465
            class: javax.net.ssl.SSLSocketFactory
            fallback: false
          ssl:
            enable: true


================================================
FILE: config/src/main/resources/shared/registry.yml
================================================
server:
  port: 8761

================================================
FILE: config/src/main/resources/shared/statistics-service.yml
================================================
security:
  oauth2:
    client:
      clientId: statistics-service
      clientSecret: ${STATISTICS_SERVICE_PASSWORD}
      accessTokenUri: http://auth-service:5000/uaa/oauth/token
      grant-type: client_credentials
      scope: server

spring:
  data:
    mongodb:
      host: statistics-mongodb
      username: user
      password: ${MONGODB_PASSWORD}
      database: piggymetrics
      port: 27017

server:
  servlet:
    context-path: /statistics
  port: 7000

rates:
  url: https://api.exchangeratesapi.io

================================================
FILE: config/src/main/resources/shared/turbine-stream-service.yml
================================================


================================================
FILE: docker-compose.dev.yml
================================================
version: '2.1'
services:
  rabbitmq:
    ports:
      - 5672:5672

  config:
    build: config
    ports:
      - 8888:8888

  registry:
    build: registry

  gateway:
    build: gateway

  auth-service:
    build: auth-service
    ports:
      - 5000:5000

  auth-mongodb:
    build: mongodb
    ports:
      - 25000:27017

  account-service:
    build: account-service
    ports:
      - 6000:6000

  account-mongodb:
    build: mongodb
    ports:
      - 26000:27017

  statistics-service:
    build: statistics-service
    ports:
      - 7000:7000

  statistics-mongodb:
    build: mongodb
    ports:
      - 27000:27017

  notification-service:
    build: notification-service
    ports:
      - 8000:8000

  notification-mongodb:
    build: mongodb
    ports:
      - 28000:27017

  monitoring:
    build: monitoring

  turbine-stream-service:
    build: turbine-stream-service

================================================
FILE: docker-compose.yml
================================================
version: '2.1'
services:
  rabbitmq:
    image: rabbitmq:3-management
    restart: always
    ports:
      - 15672:15672
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  config:
    environment:
      CONFIG_SERVICE_PASSWORD: $CONFIG_SERVICE_PASSWORD
    image: sqshq/piggymetrics-config
    restart: always
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  registry:
    environment:
      CONFIG_SERVICE_PASSWORD: $CONFIG_SERVICE_PASSWORD
    image: sqshq/piggymetrics-registry
    restart: always
    depends_on:
      config:
        condition: service_healthy
    ports:
      - 8761:8761
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  gateway:
    environment:
      CONFIG_SERVICE_PASSWORD: $CONFIG_SERVICE_PASSWORD
    image: sqshq/piggymetrics-gateway
    restart: always
    depends_on:
      config:
        condition: service_healthy
    ports:
      - 80:4000
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  auth-service:
    environment:
      CONFIG_SERVICE_PASSWORD: $CONFIG_SERVICE_PASSWORD
      NOTIFICATION_SERVICE_PASSWORD: $NOTIFICATION_SERVICE_PASSWORD
      STATISTICS_SERVICE_PASSWORD: $STATISTICS_SERVICE_PASSWORD
      ACCOUNT_SERVICE_PASSWORD: $ACCOUNT_SERVICE_PASSWORD
      MONGODB_PASSWORD: $MONGODB_PASSWORD
    image: sqshq/piggymetrics-auth-service
    restart: always
    depends_on:
      config:
        condition: service_healthy
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  auth-mongodb:
    environment:
      MONGODB_PASSWORD: $MONGODB_PASSWORD
    image: sqshq/piggymetrics-mongodb
    restart: always
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  account-service:
    environment:
      CONFIG_SERVICE_PASSWORD: $CONFIG_SERVICE_PASSWORD
      ACCOUNT_SERVICE_PASSWORD: $ACCOUNT_SERVICE_PASSWORD
      MONGODB_PASSWORD: $MONGODB_PASSWORD
    image: sqshq/piggymetrics-account-service
    restart: always
    depends_on:
      config:
        condition: service_healthy
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  account-mongodb:
    environment:
      INIT_DUMP: account-service-dump.js
      MONGODB_PASSWORD: $MONGODB_PASSWORD
    image: sqshq/piggymetrics-mongodb
    restart: always
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  statistics-service:
    environment:
      CONFIG_SERVICE_PASSWORD: $CONFIG_SERVICE_PASSWORD
      MONGODB_PASSWORD: $MONGODB_PASSWORD
      STATISTICS_SERVICE_PASSWORD: $STATISTICS_SERVICE_PASSWORD
    image: sqshq/piggymetrics-statistics-service
    restart: always
    depends_on:
      config:
        condition: service_healthy
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  statistics-mongodb:
    environment:
      MONGODB_PASSWORD: $MONGODB_PASSWORD
    image: sqshq/piggymetrics-mongodb
    restart: always
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  notification-service:
    environment:
      CONFIG_SERVICE_PASSWORD: $CONFIG_SERVICE_PASSWORD
      MONGODB_PASSWORD: $MONGODB_PASSWORD
      NOTIFICATION_SERVICE_PASSWORD: $NOTIFICATION_SERVICE_PASSWORD
    image: sqshq/piggymetrics-notification-service
    restart: always
    depends_on:
      config:
        condition: service_healthy
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  notification-mongodb:
    image: sqshq/piggymetrics-mongodb
    restart: always
    environment:
      MONGODB_PASSWORD: $MONGODB_PASSWORD
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  monitoring:
    environment:
      CONFIG_SERVICE_PASSWORD: $CONFIG_SERVICE_PASSWORD
    image: sqshq/piggymetrics-monitoring
    restart: always
    depends_on:
      config:
        condition: service_healthy
    ports:
      - 9000:8080
    logging:
      options:
        max-size: "10m"
        max-file: "10"

  turbine-stream-service:
    environment:
      CONFIG_SERVICE_PASSWORD: $CONFIG_SERVICE_PASSWORD
    image: sqshq/piggymetrics-turbine-stream-service
    restart: always
    depends_on:
      config:
        condition: service_healthy
    ports:
    - 8989:8989
    logging:
      options:
        max-size: "10m"
        max-file: "10"


================================================
FILE: gateway/Dockerfile
================================================
FROM java:8-jre
MAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>

ADD ./target/gateway.jar /app/
CMD ["java", "-Xmx200m", "-jar", "/app/gateway.jar"]

EXPOSE 4000

================================================
FILE: gateway/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<artifactId>gateway</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>gateway</name>

	<parent>
		<groupId>com.piggymetrics</groupId>
		<artifactId>piggymetrics</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-sleuth</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<finalName>${project.name}</finalName>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>


================================================
FILE: gateway/src/main/java/com/piggymetrics/gateway/GatewayApplication.java
================================================
package com.piggymetrics.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class GatewayApplication {

	public static void main(String[] args) {
		SpringApplication.run(GatewayApplication.class, args);
	}
}


================================================
FILE: gateway/src/main/resources/bootstrap.yml
================================================
spring:
  application:
    name: gateway
  cloud:
    config:
      uri: http://config:8888
      fail-fast: true
      password: ${CONFIG_SERVICE_PASSWORD}
      username: user


================================================
FILE: gateway/src/main/resources/static/attribution.html
================================================
<!DOCTYPE html>

<htmL>
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <meta name="viewport" content="width=1150, user-scalable=no">
  <title>Piggy Metrics</title>
  <link rel="stylesheet" type="text/css" href="css/launch.css">
</head>
<body>

<a href="index.html"><div id="piggy"></div></a>
<div class="CCattribution">
  <a href="http://creativecommons.org">Creative Commons</a> – Attribution (CC BY 3.0)
  <br>
  Thanks a lot for icons from <a href="http://thenounproject.com">The Noun Project</a> collection.
  <br>
  <br>
  Here's the list of all used icons:
  <br>
  Piggy Bank designed by Jezmael Basilio
  <br>
  Arrow designed by Jardson A.
  <br>
  Wallet designed by Luis Prado
  <br>
  Analytics designed by Aneeque Ahmed
  <br>
  Piggy Bank designed by Michelle Ann
  <br>
  Light Bulb designed by Chris Brunskill
  <br>
  Speech Bubble designed by Cengiz SARI
  <br>
  Bag designed by Agus Purwanto
  <br>
  Analytics designed by Luboš Volkov
  <br>
  College Tuition designed by Rediffusion
  <br>
  Marijuana designed by Gareth
  <br>
  Stroller designed by Edward Boatman
  <br>
  Television designed by Piero Borgo
  <br>
  Island designed by Bohdan Burmich
  <br>
  Light Bulb designed by Rémy Médard
  <br>
  Shirt designed by Megan Sheehan
  <br>
  Telephone designed by Ian Mawle
  <br>
  Shopping Cart designed by Megan Sheehan
  <br>
  Gas designed by Jon Testa
</div>
</body>
</html>


================================================
FILE: gateway/src/main/resources/static/css/animation.css
================================================
/* ZOOM AVATAR */
@-webkit-keyframes zoomavatar {
	0% {
		-webkit-transform: scale(0.1);
	}
	60% {
		-webkit-transform: scale(1.3);
	}
	100% {
		-webkit-transform: scale(1);
	}
}
@-moz-keyframes zoomavatar {
	0% {
		-moz-transform: scale(0.1);
	}
	80% {
		-moz-transform: scale(1.3);
	}
	100% {
		-moz-transform: scale(1);
	}
}
@-o-keyframes zoomavatar {
	0% {
		-o-transform: scale(0.1);
	}
	60% {
		-o-transform: scale(1.3);
	}
	100% {
		-o-transform: scale(1);
	}
}
@-ms-keyframes zoomavatar {
	0% {
		-ms-transform: scale(0.1);
	}
	60% {
		-ms-transform: scale(1.3);
	}
	100% {
		-ms-transform: scale(1);
	}
}
@keyframes zoomavatar {
	0% {
		transform: scale(0.1);
	}
	60% {
		transform: scale(1.3);
	}
	100% {
		transform: scale(1);
	}
}
/* UNZOOM AVATAR */
@-webkit-keyframes unzoomavatar {
	0% {
		-webkit-transform: scale(1);
	}
	40% {
		-webkit-transform: scale(1.3);
	}
	100% {
		-webkit-transform: scale(0.1);
	}
}
@-moz-keyframes unzoomavatar {
	0% {
		-moz-transform: scale(1);
	}
	40% {
		-moz-transform: scale(1.3);
	}
	100% {
		-moz-transform: scale(0.1);
	}
}
@-o-keyframes unzoomavatar {
	0% {
		-o-transform: scale(1);
	}
	40% {
		-o-transform: scale(1.3);
	}
	100% {
		-o-transform: scale(0.1);
	}
}
@-ms-keyframes unzoomavatar {
	0% {
		-ms-transform: scale(1);
	}
	40% {
		-ms-transform: scale(1.3);
	}
	100% {
		-ms-transform: scale(0.1);
	}
}
@keyframes unzoomavatar {
	0% {
		transform: scale(1);
	}
	40% {
		transform: scale(1.3);
	}
	100% {
		transform: scale(0.1);
	}
}
/* GO LEFT */
@-webkit-keyframes goleft {
	0% {
		right: 100px; left:0%;
	}
	60% {
		right: 300px; left:-20%;
	}
	100% {
		right: 300px; left:-18%;
	}
}
@-moz-keyframes goleft {
	0% {
		right: 100px; left:0%;
	}
	60% {
		right: 300px; left:-20%;
	}
	100% {
		right: 300px; left:-18%;
	}
}
@-o-keyframes goleft {
	0% {
		right: 100px; left:0%;
	}
	60% {
		right: 300px; left:-20%;
	}
	100% {
		right: 300px; left:-18%;
	}
}
@-ms-keyframes goleft {
	0% {
		right: 100px; left:0%;
	}
	60% {
		right: 300px; left:-20%;
	}
	100% {
		right: 300px; left:-18%;
	}
}
@keyframes goleft {
	0% {
		right: 100px; left:0%;
	}
	60% {
		right: 300px; left:-20%;
	}
	100% {
		right: 300px; left:-18%;
	}
}
/* GO RIGHT */
@-webkit-keyframes goright {
	0% {
		right: -100px; left:0%;
	}
	60% {
		right: -300px; left:20%;
	}
	100% {
		right: -300px; left:18%;
	}
}
@-moz-keyframes goright {
	0% {
		right: -100px; left:0%;
	}
	60% {
		right: -300px; left:20%;
	}
	100% {
		right: -300px; left:18%;
	}
}
@-o-keyframes goright {
	0% {
		right: -100px; left:0%;
	}
	60% {
		right: -300px; left:20%;
	}
	100% {
		right: -300px; left:18%;
	}
}
@-ms-keyframes goright {
	0% {
		right: -100px; left:0%;
	}
	60% {
		right: -300px; left:20%;
	}
	100% {
		right: -300px; left:18%;
	}
}
@keyframes goright {
	0% {
		right: -100px; left:0%;
	}
	60% {
		right: -300px; left:20%;
	}
	100% {
		right: -300px; left:18%;
	}
}
/* GO DOWN */
@-webkit-keyframes godown {
	0% {
		bottom:20%;
	}
	60% {
		bottom:4%;
	}
	100% {
		bottom:8%;
	}
}
@-moz-keyframes godown {
	0% {
		bottom:20%;
	}
	60% {
		bottom:4%;
	}
	100% {
		bottom:8%;
	}
}
@-o-keyframes godown {
	0% {
		bottom:20%;
	}
	60% {
		bottom:4%;
	}
	100% {
		bottom:8%;
	}
}
@-ms-keyframes godown {
	0% {
		bottom:20%;
	}
	60% {
		bottom:4%;
	}
	100% {
		bottom:8%;
	}
}
@keyframes godown {
	0% {
		bottom:20%;
	}
	60% {
		bottom:4%;
	}
	100% {
		bottom:8%;
	}
}
/* PLUS */
@-webkit-keyframes plus {
	0% {
		-webkit-transform: scale(0.85);
	}
	8% {
		-webkit-transform: scale(1);
	}
	80% {
		-webkit-transform: scale(0.85);
	}
	100% {
		-webkit-transform: scale(0.85);
	}
}
@-moz-keyframes plus {
	0% {
		-moz-transform: scale(0.85);
	}
	8% {
		-moz-transform: scale(1);
	}
	80% {
		-moz-transform: scale(0.85);
	}
	100% {
		-moz-transform: scale(0.85);
	}
}
@-o-keyframes plus {
	0% {
		-o-transform: scale(0.85);
	}
	8% {
		-o-transform: scale(1);
	}
	80% {
		-o-transform: scale(0.85);
	}
	100% {
		-o-transform: scale(0.85);
	}
}
@-ms-keyframes plus {
	0% {
		-ms-transform: scale(0.85);
	}
	8% {
		-ms-transform: scale(1);
	}
	80% {
		-ms-transform: scale(0.85);
	}
	100% {
		-ms-transform: scale(0.85);
	}
}
@keyframes plus {
	0% {
		transform: scale(0.85);
	}
	8% {
		transform: scale(1);
	}
	80% {
		transform: scale(0.85);
	}
	100% {
		transform: scale(0.85);
	}
}

/* SLIDER */
@-webkit-keyframes endoflist {
	0% {
		-webkit-transform: translateY(0px);
	}
	20% {
		-webkit-transform: translateY(-60px);
	}
	100% {
		-webkit-transform: translateY(0px);
	}
}
@-moz-keyframes endoflist {
	0% {
		-moz-transform: translateY(0px);
	}
	20% {
		-moz-transform: translateY(-60px);
	}
	100% {
		-moz-transform: translateY(0px);
	}
}
@-o-keyframes endoflist {
	0% {
		-o-transform: translateY(0px);
	}
	20% {
		-o-transform: translateY(-60px);
	}
	100% {
		-o-transform: translateY(0px);
	}
}
@-ms-keyframes endoflist {
	0% {
		-ms-transform: translateY(0px);
	}
	20% {
		-ms-transform: translateY(-60px);
	}
	100% {
		-ms-transform: translateY(0px);
	}
}
@keyframes endoflist {
	0% {
		transform: translateY(0px);
	}
	20% {
		transform: translateY(-60px);
	}
	100% {
		transform: translateY(0px);
	}
}

@-webkit-keyframes startoflist {
	0% {
		-webkit-transform: translateY(0px);
	}
	20% {
		-webkit-transform: translateY(60px);
	}
	100% {
		-webkit-transform: translateY(0px);
	}
}
@-moz-keyframes startoflist {
	0% {
		-moz-transform: translateY(0px);
	}
	20% {
		-moz-transform: translateY(60px);
	}
	100% {
		-moz-transform: translateY(0px);
	}
}
@-o-keyframes startoflist {
	0% {
		-o-transform: translateY(0px);
	}
	20% {
		-o-transform: translateY(60px);
	}
	100% {
		-o-transform: translateY(0px);
	}
}
@-ms-keyframes startoflist {
	0% {
		-ms-transform: translateY(0px);
	}
	20% {
		-ms-transform: translateY(60px);
	}
	100% {
		-ms-transform: translateY(0px);
	}
}
@keyframes startoflist {
	0% {
		transform: translateY(0px);
	}
	20% {
		transform: translateY(60px);
	}
	100% {
		transform: translateY(0px);
	}
}


@-webkit-keyframes frameanimate {
	0% {
		-webkit-transform: translateY(-284px);
	}
	50% {
		-webkit-transform: translateY(50px);
	}
	100% {
		-webkit-transform: translateY(0px);
	}
}
@-moz-keyframes frameanimate {
	0% {
		-moz-transform: translateY(-284px);
	}
	50% {
		-moz-transform: translateY(100px);
	}
	100% {
		-moz-transform: translateY(0px);
	}
}
@-o-keyframes frameanimate {
	0% {
		-o-transform: translateY(-284px);
	}
	50% {
		-o-transform: translateY(100px);
	}
	100% {
		-o-transform: translateY(0px);
	}
}
@-ms-keyframes frameanimate {
	0% {
		-ms-transform: translateY(-284px);
	}
	50% {
		-ms-transform: translateY(100px);
	}
	100% {
		-ms-transform: translateY(0px);
	}
}
@keyframes frameanimate {
	0% {
		transform: translateY(-284px);
	}
	50% {
		transform: translateY(100px);
	}
	100% {
		transform: translateY(0px);
	}
}

/*MODAL WINDOWS*/

/* MODAL FORWARD */
@-webkit-keyframes modalforward {
	0% {
		-webkit-transform: scale(0.4);
	}
	60% {
		-webkit-transform: scale(1.1);
	}
	100% {
		-webkit-transform: scale(1);
	}
}
@-moz-keyframes modalforward {
	0% {
		-moz-transform: scale(0.4);
	}
	80% {
		-moz-transform: scale(1.1);
	}
	100% {
		-moz-transform: scale(1);
	}
}
@-o-keyframes modalforward {
	0% {
		-o-transform: scale(0.4);
	}
	60% {
		-o-transform: scale(1.1);
	}
	100% {
		-o-transform: scale(1);
	}
}
@-ms-keyframes modalforward {
	0% {
		-ms-transform: scale(0.4);
	}
	60% {
		-ms-transform: scale(1.1);
	}
	100% {
		-ms-transform: scale(1);
	}
}
@keyframes modalforward {
	0% {
		transform: scale(0.4);
	}
	60% {
		transform: scale(1.1);
	}
	100% {
		transform: scale(1);
	}
}
/* UNZOOM REVERSE */
@-webkit-keyframes modalreverse {
	0% {
		-webkit-transform: scale(1);
	}
	40% {
		-webkit-transform: scale(1.06);
	}
	100% {
		-webkit-transform: scale(0.6);
	}
}
@-moz-keyframes modalreverse {
	0% {
		-moz-transform: scale(1);
	}
	40% {
		-moz-transform: scale(1.06);
	}
	100% {
		-moz-transform: scale(0.6);
	}
}
@-o-keyframes modalreverse {
	0% {
		-o-transform: scale(1);
	}
	40% {
		-o-transform: scale(1.06);
	}
	100% {
		-o-transform: scale(0.6);
	}
}
@-ms-keyframes modalreverse {
	0% {
		-ms-transform: scale(1);
	}
	40% {
		-ms-transform: scale(1.06);
	}
	100% {
		-ms-transform: scale(0.6);
	}
}
@keyframes modalreverse {
	0% {
		transform: scale(1);
	}
	40% {
		transform: scale(1.06);
	}
	100% {
		transform: scale(0.6);
	}
}
/* MODAL VALUE ERROR */
@-webkit-keyframes modalvalueerror {
	0% {
		-webkit-transform: scale(1);
	}
	50% {
		-webkit-transform: scale(1.5);
	}
	100% {
		-webkit-transform: scale(1);
	}
}
@-moz-keyframes modalvalueerror {
	0% {
		-moz-transform: scale(1);
	}
	40% {
		-moz-transform: scale(1.5);
	}
	100% {
		-moz-transform: scale(1);
	}
}
@-o-keyframes modalvalueerror {
	0% {
		-o-transform: scale(1);
	}
	40% {
		-o-transform: scale(1.5);
	}
	100% {
		-o-transform: scale(1);
	}
}
@-ms-keyframes modalvalueerror {
	0% {
		-ms-transform: scale(1);
	}
	40% {
		-ms-transform: scale(1.5);
	}
	100% {
		-ms-transform: scale(1);
	}
}
@keyframes modalvalueerror {
	0% {
		transform: scale(1);
	}
	40% {
		transform: scale(1.5);
	}
	100% {
		transform: scale(1);
	}
}
/* NEW ITEM ADDED */
@-webkit-keyframes newitemadded {
	20% {
		background-color: #f2f2f2;
	}
	70% {
		background-color: #f2f2f2;
	}
	100% {
		background-color: white;
	}
}
@-moz-keyframes newitemadded {
	30% {
		background-color: #f2f2f2;
	}
	70% {
		background-color: #f2f2f2;
	}
	100% {
		background-color: white;
	}
}
@-o-keyframes newitemadded {
	30% {
		background-color: #f2f2f2;
	}
	70% {
		background-color: #f2f2f2;
	}
	100% {
		background-color: white;
	}
}
@-ms-keyframes newitemadded {
	30% {
		background-color: #f2f2f2;
	}
	70% {
		background-color: #f2f2f2;
	}
	100% {
		background-color: white;
	}
}
@keyframes newitemadded {
	30% {
		background-color: #f2f2f2;
	}
	70% {
		background-color: #f2f2f2;
	}
	100% {
		background-color: white;
	}
}
/* BUBBLE */

@-webkit-keyframes bubble {
	5% {
		opacity: 0;
		background-position: -280px 0;
		top: 21px; right: 10px;
	}
	10% {
		opacity: 0;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	40% {
		opacity: 1;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	80% {
		opacity: 1;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	90% {
		opacity: 0;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	95% {
		opacity: 0;
		background-position: -280px 0;
		top: 21px; right: 10px;
	}
	100% {
		opacity: 1;
		background-position: -280px 0;
		top: 21px; right: 10px;
	}
}
@-moz-keyframes bubble {
	5% {
		opacity: 0;
		background-position: -280px 0;
		top: 21px; right: 10px;
	}
	10% {
		opacity: 0;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	40% {
		opacity: 1;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	80% {
		opacity: 1;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	90% {
		opacity: 0;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	95% {
		opacity: 0;
		background-position: -280px 0;
		top: 21px; right: 10px;
	}
	100% {
		opacity: 1;
		background-position: -280px 0;
		top: 21px; right: 10px;
	}
}
@keyframes bubble {
	5% {
		opacity: 0;
		background-position: -280px 0;
		top: 21px; right: 10px;
	}
	10% {
		opacity: 0;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	40% {
		opacity: 1;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	80% {
		opacity: 1;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	90% {
		opacity: 0;
		background-position: -240px 0;
		top: 12px; right: 12px;
	}
	95% {
		opacity: 0;
		background-position: -280px 0;
		top: 21px; right: 10px;
	}
	100% {
		opacity: 1;
		background-position: -280px 0;
		top: 21px; right: 10px;
	}
}
@-webkit-keyframes spincircle {
	0% {
		-webkit-transform: rotate(0deg);
	}
	95% {
		-webkit-transform: rotate(360deg);
	}
	100% {
		-webkit-transform: rotate(370deg);
	}
}
@-moz-keyframes spincircle {
	0% {
		-moz-transform: rotate(0deg);
	}
	95% {
		-moz-transform: rotate(360deg);
	}
	100% {
		-moz-transform: rotate(370deg);
	}
}
@-o-keyframes spincircle {
	0% {
		-o-transform: rotate(0deg);
	}
	95% {
		-o-transform: rotate(360deg);
	}
	100% {
		-o-transform: rotate(370deg);
	}
}
@-ms-keyframes spincircle {
	0% {
		-ms-transform: rotate(0deg);
	}
	95% {
		-ms-transform: rotate(360deg);
	}
	100% {
		-ms-transform: rotate(370deg);
	}
}
@keyframes spincircle {
	0% {
		transform: rotate(0deg);
	}
	95% {
		-transform: rotate(360deg);
	}
	100% {
		transform: rotate(370deg);
	}
}


================================================
FILE: gateway/src/main/resources/static/css/launch.css
================================================
#createaccount, #enter, #secondenter, #info, #backlogin, #backpassword, #plusavatar, .columnimage  {
	background: url("../images/1pagesprites.png") no-repeat;
	background-size: 650px 197px;
}

@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min-resolution: 144dpi) {
	#createaccount, #enter, #secondenter, #info, #backlogin, #backpassword, #plusavatar, .columnimage {
		background: url("../images/1pagesprites@2x.png") no-repeat;
		background-size: 650px 197px;
	}
}

/*========================== CARDS WRAPPER ===========================*/

#loginpage {
	top:0; bottom: 0; left:0; right: 0;
	position: absolute;
	margin: auto;
	width: 300px;
	height: 500px;
	-webkit-perspective: 1000px;
	-moz-perspective: 1000px;
	-ms-perspective: 1000px;
	-o-perspective: 1000px;
	perspective: 1000px;
	display: none;
}
.CCattribution {
	position: relative;
	top: 50px;
	text-align: center;
	font-family: "Helvetica", "Arial";
	font-size: 12px;
	line-height: 30px;
	color: #525252;
	padding-bottom: 90px;
}
.CCattribution a {
	color: #7ba1b4;
}

#loginpage, .front, .back {
	width: 300px;
	height: 500px;
}
#flipper {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	-ms-transform-style: preserve-3d;
	-o-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-moz-backface-visibility: hidden;
	-webkit-transition: 1000ms;
	-moz-transition: 1000ms;
	-ms-transition: 1000ms;
	-o-transition: 1000ms;
	transition: 1000ms;
	position: relative;
	overflow: visible;
}
.flippedcardinfo {
	-webkit-transform: rotateY(180deg);
	-moz-transform: rotateY(180deg);
	-ms-transform: rotateY(180deg);
	-o-transform: rotateY(180deg);
	transform: rotateY(180deg);
}
.FRONTCARD, .BACKCARD {
	-webkit-backface-visibility: hidden;
	-moz-backface-visibility: hidden;
	-ms-backface-visibility: hidden;
	-o-backface-visibility: hidden;
	backface-visibility: hidden;
	overflow: visible;
	top:0; bottom: 0; left:0; right: 0;
	position: absolute;
	text-align: center;
	width: 300px;
}
.fliptext {
	position: absolute;
	text-transform: uppercase;
	left: 0px; right: 0px; bottom: -10px;
	height: 30px;
	font-size: 11px;
	color: #6e6e6e;
	line-height: 0.95em;
	display: inline-block;
	font-family: Arial;
	background-color: white;
}
.fliptext a{
	color: #96bcce;
	text-decoration: none;
	border-bottom: 1px dashed #96bcce;
}
.fliptext a:hover{
	color: #7ba1b4;
	text-decoration: none;
	border-bottom: 1px dashed #7ba1b4;
}

/*================================= FIRST CARD =================================*/
.FRONTCARD {
	z-index: 2;
	height: 450px;
	background-color: white;
	-webkit-transform: rotateY(0deg);
	-moz-transform: rotateY(0deg);
	-ms-transform: rotateY(0deg);
	-o-transform: rotateY(0deg);
	transform: rotateY(0deg);
}
.auto-shake{
	-webkit-animation: 1s auto-shake ease-out;
	-moz-animation: 1s auto-shake ease-out;
	-o-animation: 1s auto-shake ease-out;
	-ms-animation: 1s auto-shake ease-out;
	animation: 1s auto-shake ease-out;
}
.hover-shake{
	-webkit-animation: 1.6s hover-shake ease-out;
	-moz-animation: 1.6s hover-shake ease-out;
	-o-animation: 1.6s hover-shake ease-out;
	-ms-animation: 1.6s hover-shake ease-out;
	animation: 1.6s hover-shake ease-out;
}
.loadingspin{
	-webkit-animation: 2s loadingspin;
	-moz-animation: 2s loadingspin;
	-o-animation: 2s loadingspin;
	-ms-animation: 2s loadingspin;
	animation: 2s loadingspin;
}
#piggy {
	display: block;
	background: url("../images/piggy_large.gif") no-repeat;
	background-size: 178px 178px;
	width: 178px;
	height: 178px;
	position: relative;
	margin: auto;
	z-index: 50;
}
#enter, #secondenter {
	-webkit-animation: enterarrow 2s infinite;
	-moz-animation: enterarrow 2s infinite;
	-o-animation: enterarrow 2s infinite;
	-ms-animation: enterarrow 2s infinite;
	animation: enterarrow 2s infinite;
	background-position: -190px -60px;
	margin-left: 222px;
	margin-top: 18px;
	width: 52px;
	height: 12px;
	position: absolute;
	cursor: pointer;
	display: none;
	z-index: 7;
}
#secondenter{
	position: absolute;
	bottom: 85px;
	z-index: 4;
}
#preloader{
	background: url("../images/preloader.gif") center no-repeat;
	background-size: 18px 18px;
	margin-left: 210px;
	bottom: 69px;
	position: absolute;
	display: none;
	width: 52px;
	height: 46px;
	z-index: 5;
}

/*FLIP BUTTON*/
#wrapper {
	display: block;
	font-size: 13px;
	color: black;
	position: absolute;
	top: 335px;
	width: 300px;
	height: 46px;
	-webkit-perspective: 1100px;
	-moz-perspective: 1100px;
	-ms-perspective: 1100px;
	-o-perspective: 1100px;
	perspective: 1100px;
	-ms-transform: rotated3(1,0,0,0);
	-webkit-transform-origin: 50% 46px 0;
	-moz-transform-origin: 50% 46px 0;
	-ms-transform-origin: 50% 46px 0;
	-o-transform-origin: 50% 46px 0;
	transform-origin: 10% 46px 0;
	z-index: 3;
}
#cube {
	position: absolute;
	width: 300px;
	height: 46px;
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	-ms-transform-style: preserve-3d;
	-o-transform-style: preserve-3d;
	transform-style: preserve-3d;

	-webkit-transition: all 400ms cubic-bezier(0.67, 0.07, 0.50, 0.88);
	-moz-transition: all 400ms cubic-bezier(0.67, 0.07, 0.50, 0.88);
	-ms-transition: all 400ms cubic-bezier(0.67, 0.07, 0.50, 0.88);
	-o-transition: all 400ms cubic-bezier(0.67, 0.07, 0.50, 0.88);
	transition: all 400ms cubic-bezier(0.67, 0.07, 0.50, 0.88);
}
.flippedform{
	-webkit-transform-origin: 0 46px -46px;
	-moz-transform-origin: 0 46px -46px;
	-ms-transform-origin: 0 46px -46px;
	-o-transform-origin: 0 46px -46px;
	transform-origin: 0 46px -46px;
	-webkit-transform: rotate3d(1,0,0,90deg);
	-moz-transform: rotate3d(1,0,0,90deg);
	-ms-transform: rotate3d(1,0,0,90deg);
	-o-transform: rotate3d(1,0,0,90deg);
	transform: rotate3d(1,0,0,90deg);
}
.side {
	outline: 3px double #a6ccd9;
	text-indent: 15px;
	width: 300px;
	height: 46px;
	line-height: 48px;
	position: absolute;
}
#backlogin, #backpassword  {
	display: block;
	position: absolute;
	left: 66px;
	top: 12px;
	border-color: 1px solid;
	width: 22px;
	height: 20px;
}
#backlogin {
	background-position: -250px -24px;
}
#backpassword {
	background-position: -250px 0;
}
#side1 {
	background-position: -250px -24px;
	background-color: white;
	width: 300px;
	height: 46px;
}
#side2 {
	background-color: white;
	-webkit-transform: translateZ(-23px) translateY(23px) rotateX(-90deg);
	-moz-transform: translateZ(-23px) translateY(23px) rotateX(-90deg);
	-ms-transform: translateZ(-23px) translateY(23px) rotateX(-90deg);
	-o-transform: translateZ(-23px) translateY(23px) rotateX(-90deg);
	transform: translateZ(-23px) translateY(23px) rotateX(-90deg);
}

/* END OF FLIP BUTTON */

#logotext {
	background: url("../images/logotext_large.gif") no-repeat;
	background-size: 172px 65px;
	width: 172px;
	height: 65px;
	position: relative;
	margin: auto;
	margin-top: 36px;
}
#info {
	background-position: -190px 0;
	cursor: pointer;
	width: 49px;
	height: 49px;
	position: absolute;
	margin: auto;
	top:-10px;
	right: -20px;
}

/* FIRST CARD FORMS */

input[class="frontforms"]{
	border: 0px solid;
	position: relative;
	color: #4c4c4c;
	font-family: Arial;
	font-size: 15px;
}
input[id="frontloginform"]{
	margin-left: 20px;
	height: 25px;
	width: 110px;
}
input[id="frontpasswordform"]{
	margin-left: 25px;
	height: 25px;
	width: 95px;
}
.ghostform {
	display: none;
}

input[class="backforms"]:focus { outline: none; }
input[class="backforms"]::-webkit-input-placeholder{font-family: Arial; font-size: 15px; color: #cdcdcd;}
input[class="backforms"]:-ms-input-placeholder{font-family: Arial; font-size: 15px; color: #cdcdcd;}
input[class="backforms"]:-moz-placeholder{font-family: Arial; font-size: 15px; color: #cdcdcd;}
input[type="text"]:focus, input[type="password"]:focus { outline: none; }
input[class="frontforms"]::-webkit-input-placeholder{font-family: Arial; font-size: 15px; color: #cdcdcd;}
input[class="frontforms"]:-ms-input-placeholder{font-family: Arial; font-size: 15px; color: #cdcdcd;}
input[class="frontforms"]:-moz-placeholder{font-family: Arial; font-size: 15px; color: #cdcdcd;}

/*================================= SECOND CARD =================================*/

.BACKCARD {
	-webkit-transform: rotateY(180deg);
	-moz-transform: rotateY(180deg);
	-ms-transform: rotateY(180deg);
	-o-transform: rotateY(180deg);
	transform: rotateY(180deg);
	background-color: white;
	z-index: 1;
	height: 500px;
}
#franklin{
	border: 1px solid #b9d6dc;
	-webkit-border-radius: 90px;
	-ms-border-radius: 90px;
	-o-border-radius: 90px;
	-moz-border-radius: 90px;
	border-radius: 90px;
	top:0; left: 0; right: 0; bottom: 0;
	position: relative;
	margin: auto;
	width: 162px;
	height: 162px;

}
#plusavatar {
	-webkit-transition: 0.4s;
	-moz-transition: 0.4s;
	-o-transition: 0.4s;
	-ms-transition: 0.4s;
	transition: 0.4s;
	opacity: 0;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);
	width: 180px;
	height: 180px;
	position: absolute;
	top:10px; left:0; right: 0;
	background-position: 0 -40px;
	margin: auto;
	z-index: 2;
}
.avataranimation {
	-webkit-animation: 2.5s plusavatar;
	-moz-animation: 2.5s plusavatar;
	-o-animation: 2.5s plusavatar;
	-ms-animation: 2.5s plusavatar;
	animation: 2.5s plusavatar;
}
.infiniteavataranimation {
	-webkit-animation: 1.5s infinite plusavatar;
	-moz-animation: 1.5s infinite plusavatar;
	-o-animation: 1.5s infinite plusavatar;
	-ms-animation: 1.5s infinite plusavatar;
	animation: 1.5s infinite plusavatar;
}

#createaccount {
	background-position: -190px -80px;
	width: 134px;
	height: 44px;
	position: relative;
	margin: auto;
	margin-top: 24px;
}
.inputWrapper {
	top:-335px; left: 0; right: 0; bottom: 0;
	margin: auto;
	overflow: hidden;
	position: absolute;
	cursor: pointer;
	width: 180px;
	height: 180px;
	z-index: 3;
}

.hidden {
	opacity: 0;
	-moz-opacity: 0;
	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0)
}
.upload {
	-webkit-animation: plus 2s infinite;
	-moz-animation: plus 2s infinite;
	-o-animation: plus 2s infinite;
	-ms-animation: plus 2s infinite;
	animation: plus 2s infinite;
}
#mailform {
	position: absolute;
	top: 190px;
	margin: auto;
	right:-120px;
	text-transform: uppercase;
	width: 540px;
	height: 330px;
	font-size: 13px;
	display: block;
	opacity: 0.9;
	display: none;
}
.mailforminfo {
	position: relative;
	text-transform: none;
	top:-60px;
	font-family: "Museo-500";
	font-size: 12px;
	color: #525252;
}
.mailforminfosmall {
	font-size: 11px;
	position: relative;
	top: 30px;
	line-height: 1.7;
}
#skipmail a {
	position: relative;
	text-transform: uppercase;
	left: 0px; right: 0px; bottom: -193px;
	font-size: 11px;
	font-family: Arial;
	color: #96bcce;
	text-decoration: none;
	border-bottom: 1px dashed #96bcce;
}

#skipmail a:hover{
	color: #7ba1b4;
	text-decoration: none;
	border-bottom: 1px dashed #7ba1b4;
}

/* SECOND CARD FORMS */

#registrationforms {
	position: relative;
	top: 36px;
	line-height: 3.3em;
}
input[class="backforms"]{
	text-align: center;
	border: 1px solid #a6ccd9;
	color: #4c4c4c;
	font-family: Arial;
	font-size: 15px;
	height: 30px;
	width: 296px;
}
input[id="backmailform"] {
	position: relative;
	text-align: center;
	border: 1px solid #a6ccd9;
	color: #4c4c4c;
	font-family: Arial;
	font-size: 15px;
	height: 30px;
	width: 296px;
	top: 140px;
}
.regbutton, .demobutton, .mailbutton {
	cursor: pointer;
	position: relative;
	background-color: white;
	border: 0px solid;
	outline: 3px double #a6ccd9;
	text-transform: uppercase;
	text-shadow: 1px 1px 1px white;
	color: #6e6e6e;
}
.regbutton:hover, .demobutton:hover, .mailbutton:hover  {
	background-color: #f4f9fb;
}
.regbutton:active, .demobutton:active, .mailbutton:active  {
	background-color: #ecf3f6;
}

.regbutton {
	height: 34px;
	width: 195px;
	top:18px;
	font-size: 11px;
}
.demobutton {
	letter-spacing: 3px;
	height: 50px;
	width: 300px;
	top: 436px;
	font-size: 12px;
}
.mailbutton {
	position: relative;
	height: 34px;
	width: 195px;
	top: 178px;
	font-size: 11px;
}

/* THIRD CARD */
.flipinfo, .frominfo {
	cursor: pointer;
}
.infoflipback {
	position: absolute;
	top: -12%;
	width: 100%;
	height: 500px;
	cursor: pointer;
}
#infopage {
	margin-left: -290px;
	margin-top: -90px;
	height: 660px;
	width: 870px;
	background-color: white;
	z-index: 4;
	display: none;
	position: absolute;
	color: #525252;
}
#regpage {
	display: block;
}
#infosubtitle, #infotitle, #infofooter, #iconsfooter {
	cursor: pointer;
	font-family: "Museo-500";
	position: absolute;
	left: 0; right: 0;
	margin: auto;
	width: 100%;
}
#infosubtitle {
	text-transform: uppercase;
	font-size: 11px;
	top: 0;
	height: 30px;
}
#infotitle {
	text-transform: uppercase;
	font-size: 27px;
	top: 35px;
	height: 40px;
}
a#infofooter {
	background-image: url("../images/github.gif");
	background-size: 25px 25px;
	background-repeat: no-repeat;
	background-position: center;
	color: #757575;
	text-decoration: none;
	display: block;
	line-height: 120px;
	font-size: 12px;
	bottom: 30px;
	margin: auto;
	width: 20%;
	height: 25px;
}
a#iconsfooter {
	background-position: center;
	color: #757575;
	text-decoration: none;
	font-size: 10px;
	bottom: -30px;
}
#infoline {
	position: relative;
	width: 610px;
	display: block;
	margin: auto;
	top: 425px;
	border-top: 1px solid #b8d9e1;
}
#infolinetext {
	font-family: "Museo-500";
	text-transform: uppercase;
	letter-spacing: 2px;
	font-size: 10px;
	line-height: 30px;
	position: relative;
	width: 245px;
	height: 30px;
	display: block;
	margin: auto;
	top: 410px;
	background-color: white;
}
.infocolumn {
	position: absolute;
	top: 150px;
	margin: auto;
	display: block;
	width: 286px;
	height: 236px;
	overflow: hidden;
}
#infoleft {
	left:0;
}
#inforight {
	right:0;
}
#infocenter {
	left:0; right:0;
}
.columnimage {
	width: 104px;
	height: 104px;
	position: absolute;
	margin: auto;
	left:0; right: 0; top: 30px;
}
#leftcolumn > .columnimage {
	background-position: -546px 0;
}
#rightcolumn > .columnimage {
	background-position: -330px 0;
}
#centercolumn > .columnimage {
	background-position: -436px 0;
}
#leftcolumn, #rightcolumn, #centercolumn {
	-moz-transition: 0.8s;
	-o-transition: 0.8s ease-out;
	-ms-transition: 0.8s ease-out;
	-webkit-transition: 0.8s;
	transition: 0.8s;
	font-family: "Museo-500";
	font-size: 12px;
	width: 100%;
	height: 200%;
	position: absolute;
	padding-top: 157px;
	text-align: center;
	top: 0%;
}
#leftcolumn:hover, #rightcolumn:hover, #centercolumn:hover {
	top:-100%;
}
.columnfooter {
	position: relative;
	top: 150px;
	font-size: 11px;
	line-height: 17px;
}

@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min-resolution: 144dpi) {
	#piggy {
		background-image: url("../images/piggy_large@2x.gif");
	}
	#logotext {
		background-image: url("../images/logotext_large@2x.gif");
	}
}

/* ANIMATION */

/* SPIN THAT SHIT */

@-webkit-keyframes auto-shake {
	0% {
		-webkit-transform: rotate(0deg);
	}
	35% {
		-webkit-transform: rotate(55deg);
	}
	50% {
		-webkit-transform: rotate(-35deg);
	}
	70% {
		-webkit-transform: rotate(20deg);
	}
	90% {
		-webkit-transform: rotate(-10deg);
	}
	100% {
		-webkit-transform: rotate(0deg);
	}
}
@-moz-keyframes auto-shake {
	0% {
		-moz-transform: rotate(0deg);
	}
	35% {
		-moz-transform: rotate(55deg);
	}
	50% {
		-moz-transform: rotate(-35deg);
	}
	70% {
		-moz-transform: rotate(20deg);
	}
	90% {
		-moz-transform: rotate(-10deg);
	}
	100% {
		-moz-transform: rotate(0deg);
	}
}
@-o-keyframes auto-shake {
	0% {
		-o-transform: rotate(0deg);
	}
	35% {
		-o-transform: rotate(55deg);
	}
	50% {
		-o-transform: rotate(-35deg);
	}
	70% {
		-o-transform: rotate(20deg);
	}
	90% {
		-o-transform: rotate(-10deg);
	}
	100% {
		-o-transform: rotate(0deg);
	}
}
@-ms-keyframes auto-shake {
	0% {
		-ms-transform: rotate(0deg);
	}
	35% {
		-ms-transform: rotate(55deg);
	}
	50% {
		-ms-transform: rotate(-35deg);
	}
	70% {
		-ms-transform: rotate(20deg);
	}
	90% {
		-ms-transform: rotate(-10deg);
	}
	100% {
		-ms-transform: rotate(0deg);
	}
}
@keyframes auto-shake {
	0% {
		transform: rotate(0deg);
	}
	35% {
		transform: rotate(55deg);
	}
	50% {
		transform: rotate(-35deg);
	}
	70% {
		transform: rotate(20deg);
	}
	90% {
		transform: rotate(-10deg);
	}
	100% {
		transform: rotate(0deg);
	}
}

/* SPIN AGAIN */

@-webkit-keyframes hover-shake {
	0% {
		-webkit-transform: rotate(0deg);
	}
	30% {
		-webkit-transform: rotate(-30deg);
	}
	50% {
		-webkit-transform: rotate(20deg);
	}
	70% {
		-webkit-transform: rotate(-10deg);
	}
	90% {
		-webkit-transform: rotate(5deg);
	}
	100% {
		-webkit-transform: rotate(0deg);
	}
}
@-moz-keyframes hover-shake {
	0% {
		-moz-transform: rotate(0deg);
	}
	30% {
		-moz-transform: rotate(-30deg);
	}
	50% {
		-moz-transform: rotate(20deg);
	}
	70% {
		-moz-transform: rotate(-10deg);
	}
	90% {
		-moz-transform: rotate(5deg);
	}
	100% {
		-moz-transform: rotate(0deg);
	}
}
@-o-keyframes hover-shake {
	0% {
		-o-transform: rotate(0deg);
	}
	30% {
		-o-transform: rotate(-30deg);
	}
	50% {
		-o-transform: rotate(20deg);
	}
	70% {
		-o-transform: rotate(-10deg);
	}
	90% {
		-o-transform: rotate(5deg);
	}
	100% {
		-o-transform: rotate(0deg);
	}
}
@-ms-keyframes hover-shake {
	0% {
		-ms-transform: rotate(0deg);
	}
	30% {
		-ms-transform: rotate(-30deg);
	}
	50% {
		-ms-transform: rotate(20deg);
	}
	70% {
		-ms-transform: rotate(-10deg);
	}
	90% {
		-ms-transform: rotate(5deg);
	}
	100% {
		-ms-transform: rotate(0deg);
	}
}
@keyframes hover-shake {
	0% {
		transform: rotate(0deg);
	}
	30% {
		ransform: rotate(-30deg);
	}
	50% {
		transform: rotate(20deg);
	}
	70% {
		transform: rotate(-10deg);
	}
	90% {
		transform: rotate(5deg);
	}
	100% {
		transform: rotate(0deg);
	}
}

/*LOADING SPIN*/

@-webkit-keyframes loadingspin {
	0% {
		-webkit-transform: rotate(0deg);
	}
	20% {
		-webkit-transform: rotate(70deg);
	}
	70% {
		-webkit-transform: rotate(-400deg);
	}
	100% {
		-webkit-transform: rotate(-360deg);
	}
}
@-moz-keyframes loadingspin {
	0% {
		-moz-transform: rotate(0deg);
	}
	20% {
		-moz-transform: rotate(70deg);
	}
	70% {
		-moz-transform: rotate(-400deg);
	}
	100% {
		-moz-transform: rotate(-360deg);
	}
}
@-o-keyframes loadingspin {
	0% {
		-o-transform: rotate(0deg);
	}
	20% {
		-o-transform: rotate(70deg);
	}
	70% {
		-o-transform: rotate(-400deg);
	}
	100% {
		-o-transform: rotate(-360deg);
	}
}
@-ms-keyframes loadingspin {
	0% {
		-ms-transform: rotate(0deg);
	}
	20% {
		-ms-transform: rotate(70deg);
	}
	70% {
		-ms-transform: rotate(-400deg);
	}
	100% {
		-ms-transform: rotate(-360deg);
	}
}
@keyframes loadingspin {
	0% {
		transform: rotate(0deg);
	}
	20% {
		transform: rotate(70deg);
	}
	70% {
		transform: rotate(-400deg);
	}
	100% {
		transform: rotate(-360deg);
	}
}

/* ENTER ARROW */

@-webkit-keyframes enterarrow {
	0% {
		left: 0px;
	}
	5% {
		left: -5px;
	}
	15% {
		left: 0px;
	}
	20% {
		left: -5px;
	}
	35% {
		left: 0px;
	}
	100% {
		left: 0px;
	}
}
@-moz-keyframes enterarrow {
	0% {
		left: 0px;
	}
	5% {
		left: -5px;
	}
	15% {
		left: 0px;
	}
	20% {
		left: -5px;
	}
	35% {
		left: 0px;
	}
	100% {
		left: 0px;
	}
}
@-o-keyframes enterarrow {
	0% {
		left: 0px;
	}
	5% {
		left: -5px;
	}
	15% {
		left: 0px;
	}
	20% {
		left: -5px;
	}
	35% {
		left: 0px;
	}
	100% {
		left: 0px;
	}
}
@-ms-keyframes enterarrow {
	0% {
		left: 0px;
	}
	5% {
		left: -5px;
	}
	15% {
		left: 0px;
	}
	20% {
		left: -5px;
	}
	35% {
		left: 0px;
	}
	100% {
		left: 0px;
	}
}
@keyframes enterarrow {
	0% {
		left: 0px;
	}
	5% {
		left: -5px;
	}
	15% {
		left: 0px;
	}
	20% {
		left: -5px;
	}
	35% {
		left: 0px;
	}
	100% {
		left: 0px;
	}
}

/*PLUS AVATAR*/

@-webkit-keyframes plusavatar {
	0% {
		opacity: 0;
	}
	30% {
		opacity: 1;
	}
	80% {
		opacity: 1;
	}
	100% {
		opacity: 0;
	}
}
@-moz-keyframes plusavatar {
	0% {
		opacity: 0;
	}
	60% {
		opacity: 1;
	}
	80% {
		opacity: 1;
	}
	100% {
		opacity: 0;
	}
}
@-o-keyframes plusavatar {
	0% {
		opacity: 0;
	}
	60% {
		opacity: 1;
	}
	80% {
		opacity: 1;
	}
	100% {
		opacity: 0;
	}
}
@-ms-keyframes plusavatar {
	0% {
		opacity: 0;
	}
	60% {
		opacity: 1;
	}
	80% {
		opacity: 1;
	}
	100% {
		opacity: 0;
	}
}
@keyframes plusavatar {
	0% {
		opacity: 0;
	}
	60% {
		opacity: 1;
	}
	80% {
		opacity: 1;
	}
	100% {
		opacity: 0;
	}
}

================================================
FILE: gateway/src/main/resources/static/css/style.css
================================================
@font-face {
	font-family: 'Museo-100';
	src: url('../fonts/museo-100/museo-100.eot');
	src: local('@%@'),
	url('../fonts/museo-100/museo-100.eot?#iefix') format('embedded-opentype'),
	url('../fonts/museo-100/museo-100.woff') format('woff'),
	url('../fonts/museo-100/museo-100.svg') format('svg'),
	url('../fonts/museo-100/museo-100.ttf') format('truetype');
	font-weight: normal;
	font-style: normal;
}
@font-face {
	font-family: 'Museo-300';
	src: url('../fonts/museo-300/museo-300.eot');
	src: local('@%@'),
	url('../fonts/museo-300/museo-300.eot?#iefix') format('embedded-opentype'),
	url('../fonts/museo-300/museo-300.woff') format('woff'),
	url('../fonts/museo-300/museo-300.svg') format('svg'),
	url('../fonts/museo-300/museo-300.ttf') format('truetype');
	font-weight: normal;
	font-style: normal;
}
@font-face {
	font-family: 'Museo-500';
	src: url('../fonts/museo-500/museo-500.eot');
	src: local('@%@'),
	url('../fonts/museo-500/museo-500.eot?#iefix') format('embedded-opentype'),
	url('../fonts/museo-500/museo-500.woff') format('woff'),
	url('../fonts/museo-500/museo-500.svg') format('svg'),
	url('../fonts/museo-500/museo-500.ttf') format('truetype');
	font-weight: normal;
	font-style: normal;
}
body {
	font-family: "Museo-300", Arial;
	-webkit-font-smoothing: antialiased;
	margin: auto;
	width: 100%;
	height: 100%;
	-webkit-user-select: none;
	-moz-user-select: none;
	-o-user-select: none;
	-ms-user-select: none;
	overflow: hidden;
}
.toppage, .bottompage {
	-webkit-transition: all 0.6s cubic-bezier(0.94, 0.06, 0.05, 0.95);
	-moz-transition: all0.6s cubic-bezier(0.77, 0, 0.175, 1);
	-ms-transition: all 0.6s cubic-bezier(0.77, 0, 0.175, 1);
	-o-transition: all 0.6s cubic-bezier(0.77, 0, 0.175, 1);
	transition: all 0.6s cubic-bezier(0.77, 0, 0.175, 1);
	position: absolute;
	display: block;
	width: 100%;
	height: 100%;
}
.toppage {
	top:0;
	width: 100%;
	height: 100%;
	display: block;
}
.bottompage {
	top:100%;
	width: 100%;
	height: 100%;
	display: none;
	z-index: 600;
}
.sectionup {
	-webkit-transform: translateY(100%);
	-moz-transform: translateY(100%);
	-o-transform: translateY(100%);
	-ms-transform: translateY(100%);
	transform: translateY(100%);
}
.sectionDown {
	-webkit-transform: translateY(-100%);
	-moz-transform: translateY(-100%);
	-o-transform: translateY(-100%);
	-ms-transform: translateY(-100%);
	transform: translateY(-100%);
}
input::-ms-clear {
	display: none;
}
input[type="text"], input[type="password"], textarea {
	-webkit-appearance: none;
	box-shadow: none;
	-webkit-box-shadow: none;
	-webkit-border-radius: 0px;
	-moz-border-radius: 0px;
	border-radius: 0px;
}
::-moz-selection {
	background: rgb(255, 221, 45);
}
::selection {
	background: rgb(255, 221, 45);
}
*:focus {outline:0px none transparent;}

#bubble, #indicator, #save, #piggyicon, #rublesign, .arrowup, .arrowdown, .incomes-sprite-title, .close-sign, .modal-save-icon, #modaldeletecross, .initicons-arrow, .expenses-sprite-title, .savings-sprite-title, .triangle, .noUi-handle, .noUi-handle:after  {
	background-size: 538px 84px;
}
#chooseicon, .itembackground, .iconbox, .itemlinebackground, #circle-select-1-back, #circle-select-2-back, #circle-select-3-back {
	background-image: url("../images/icons.png");
	background-size: 1031px 42px;
	width: 42px;
	height: 42px;
}
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min-resolution: 144dpi) {
	#chooseicon, .itembackground, .iconbox, .itemlinebackground, #circle-select-1-back, #circle-select-2-back, #circle-select-3-back {
		background-image: url("../images/icons@2x.png");
	}
}
.selectbox .select {
	width: 55px;
	height: 24px;
	padding: 0 45px 0 10px;
	font: 12px/24px Arial;
	border: 1px solid #ccc;
}
.selectbox .dropdown {
	top: 25px;
	width: 110px;
	margin: 0;
	padding: 0 0;
	background: #FFF;
	border: 1px solid #ccc;
	font: 12px Arial;
}
.selectbox .select .text {
	display: block;
	width: 100%;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow: hidden;
}
.selectbox {
	color: #333;
	vertical-align: middle;
	cursor: pointer;
	margin-bottom: 26px;
}
.selectbox .trigger .arrow {
	position: absolute;
	top: 11px;
	right: 10px;
	border-left: 3px solid transparent;
	border-right: 3px solid transparent;
	border-top: 3px solid #a1a1a1;
	width: 0;
	height: 0;
	overflow: hidden;
}
.selectbox .select:active {
	background: #f8f8f8;
}
.selectbox li {
	padding: 5px 10px 6px;
}
.selectbox li.selected {
	background: #f6f6f6;
}
.selectbox li:hover {
	background: #f6f6f6;
}

#lastlogo {
	-webkit-perspective: 1000;
	-moz-perspective: 1000px;
	-ms-perspective: 1000px;
	-o-perspective: 1000px;
	perspective: 1000;
	position: absolute;
	top: 8%; left: 0; right: 0;
	margin: auto;
	z-index: 1000;
	width: 172px;
	height: 204px;
	display: none;
}
#lastlogoflipper {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	-ms-transform-style: preserve-3d;
	-o-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-moz-backface-visibility: hidden;
	-webkit-transition: 0.4s;
	-moz-transition: 0.4s;
	-ms-transition: 0.4s;
	-o-transition: 0.4s;
	transition: 0.4s;
	position: relative;
	overflow: visible;
}
#logo_greeting, #logo_settings {
	-moz-transition: 0.3s ease-out;
	-o-transition: 0.3s ease-out;
	-ms-transition: 0.3s ease-out;
	-webkit-transition: 0.3s ease-out;
	transition: 0.3s ease-out;
	background: url("../images/logo_large.gif") no-repeat;
	background-size: 137px 204px;
	background-position: center;
	width: 172px;
	height: 204px;
	position: absolute;
	margin: auto;
	left: 0; right: 0;
	display: none;
	z-index: 600;
}
#logo_greeting {
	position: absolute;
	display: none;
	top: 8%;
}
#logo_settings, #logo_statistic {
	-webkit-backface-visibility: hidden;
	-moz-backface-visibility: hidden;
	-ms-backface-visibility: hidden;
	-o-backface-visibility: hidden;
	backface-visibility: hidden;
	overflow: visible;
	position: absolute;
	cursor: pointer;
}
#logo_statistic {
	-webkit-transform: rotateY(180deg);
	-moz-transform: rotateY(180deg);
	-ms-transform: rotateY(180deg);
	-o-transform: rotateY(180deg);
	transform: rotateY(180deg);
	background: url("../images/logotext_large.gif") no-repeat;
	background-size: 172px 65px;
	width: 172px;
	height: 65px;
	position: absolute;
	cursor: pointer;
	z-index: 3000;
}
#settings_hat {
	position: absolute;
	width: 100%;
	height: 36%;
	background-color: white;
	display: none;
	z-index: 500;
}
#logoclickplace {
	width: 100%;
	height: 100%;
}
#bubble {
	position: absolute;
	top:-20px;
	right: -60px;
	background-position: -180px 0;
	width: 57px;
	height: 57px;
	cursor: pointer;
	display: none;
}
#indicator {
	position: absolute;
	background-position: -280px 0;
	top: 21px; right: 10px;
	width: 31px;
	height: 31px;
}
.bubble-animation {
	-webkit-animation: 1s bubble ease-out;
	-moz-animation: 1s bubble ease-out;
	-o-animation: 1s bubble ease-out;
	-ms-animation: 1s bubble ease-out;
	animation: 1s bubble ease-out;
}
input {
	-webkit-font-smoothing: antialiased;
}
#centerbox {
	top:0; left: 0; right: 0; bottom: 0;
	position: absolute;
	width: 250px;
	height: 250px;
	margin: auto;
	display: none;
}
#avatarcontainer {
	font-family: "Museo-100";
	border: 1px solid #b9d6dc;
	-webkit-border-radius: 90px;
	-moz-border-radius: 90px;
	border-radius: 90px;
	top:0; left: 0; right: 0; bottom: 0;
	position: absolute;
	cursor: pointer;
	width: 162px;
	height: 162px;
	margin: auto;
}
.forward {
	-webkit-animation: 0.4s zoomavatar ease-out;
	-moz-animation: 0.4s zoomavatar ease-out;
	-o-animation: 0.4s zoomavatar ease-out;
	-ms-animation: 0.4s zoomavatar ease-out;
	animation: 0.4s zoomavatar ease-out;
}
.reverse {
	-webkit-animation: 0.5s unzoomavatar ease-out;
	-moz-animation: 0.6s unzoomavatar ease-out;
	-o-animation: 0.4s unzoomavatar ease-out;
	-ms-animation: 0.4s unzoomavatar ease-out;
	animation: 0.5s unzoomavatar ease-out;
}
.avatar {
	background: url("../images/userpic.jpg") center center no-repeat;
	position: absolute;
	box-shadow:0px 0px 0px 5px white inset;
	width: 100%;
	height: 100%;
	-moz-border-radius: 90px;
	-webkit-border-radius: 90px;
	border-radius: 90px;
	background-size: 100% 100%;
}
#lefttitle, #righttitle {
	text-transform: uppercase;
	font-family: "Museo-300", Arial;
	font-size: 22px;
	position: absolute;
	text-align: center;
	display: none;
	width: 250px;
	height: 20px;
	margin: auto;
}
#lefttitle {
	-webkit-animation: 0.6s goleft ease-out;
	-moz-animation: 0.6s goleft ease-out;
	-o-animation: 0.6s goleft ease-out;
	-ms-animation: 0.6s goleft ease-out;
	animation: 0.6s goleft ease-out;
	top:0; left: -18%; right: 300px; bottom: 0;
}
#righttitle {
	-webkit-animation: 0.6s goright ease-out;
	-moz-animation: 0.6s goright ease-out;
	-o-animation: 0.6s goright ease-out;
	-ms-animation: 0.6s goright ease-out;
	animation: 0.6s goright ease-out;
	top:0; left: 18%; right: -300px; bottom: 0;
}
#bottombuttons {
	font-family: "Museo-500";
	-webkit-animation: 0.6s godown ease-out;
	-moz-animation: 0.6s godown ease-out;
	-o-animation: 0.6s godown ease-out;
	-ms-animation: 0.6s godown ease-out;
	animation: 0.6s godown ease-out;
	position: absolute;
	left: 0; right: 0; bottom: 8%;
	margin: auto;
	display: none;
	width: 90px;
	height: 25%;
}
#plus {
	text-align: center;
	text-transform: uppercase;
	font-size: 11px;
	color: #a6cbd4;
	position: absolute;
	cursor: pointer;
	margin: auto;
	width: 90px;
	height: 90px;
}
#plus:hover {
	color: #9cbac2;
}
#plusborder {
	-webkit-animation: plus 2s infinite;
	-moz-animation: plus 2s infinite;
	-o-animation: plus 2s infinite;
	-ms-animation: plus 2s infinite;
	animation: plus 2s infinite;
	position: absolute;
	border: 2px solid #cfe6ec;
	-webkit-border-radius: 70px;
	-moz-border-radius: 70px;
	border-radius: 70px;
	top:0; left: 0; right: 0; bottom: 0;
	margin: auto;
	width: 80%;
	height: 80%;
}
#plusone, #plustwo {
	position: absolute;
	top: 0; left: 0; right: 0; bottom: 0;
	margin: auto;
	background-color: #cfe6ec;
}
#plusone {
	width: 2px;
	height: 50%;
}
#plustwo {
	width: 50%;
	height: 2px;
}
#plustext {
	font-family: Arial;
	position: absolute;
	left: 0; right: 0; bottom: -15px;
	margin: auto;
}
#minus {
	top: 70%; left: 0; right: 0;
	margin: auto;
	text-transform: uppercase;
	font-size: 10px;
	color: #c8c2c4;
	position: absolute;
	cursor: pointer;
	width: 35px;
	height: 35px;
}
#minus:hover {
	color: #a39b9d;
}
#minusborder {
	position: absolute;
	border: 1px solid #c8c2c4;
	-webkit-border-radius: 70px;
	-moz-border-radius: 70px;
	border-radius: 70px;
	top:0; left: 0; right: 0; bottom: 0;
	margin: auto;
	width: 80%;
	height: 80%;
}
#minusone {
	position: absolute;
	top: 0; left: 0; right: 0; bottom: 0;
	margin: auto;
	background-color: #c8c2c4;
	width: 50%;
	height: 1px;
}
#minustext {
	width: 70px;
	text-align: center;
	font-family: Arial;
	left: -18px; right: 0; bottom: -17px;
	margin: auto;
	position: absolute;
}
.bluetext {
	color: #a6d1d6;
}
#settingspage {
	display: none;
}
#swipefield {
	position: absolute;
	width: 100%;
	height: 100%;
	z-index: 0;
}

/* =============== S L I D E R S =============== */
.incomes-sprite-title, .expenses-sprite-title, .savings-sprite-title {
	background-size: 538px 84px;
	position: absolute;
	cursor: pointer;
	top:-4px;
}
.incomes-sprite-title {
	background-position: 0 -60px;
	width: 108px;
	height: 24px;
	left: 35%;
	cursor: pointer;
}
.expenses-sprite-title {
	background-position: -114px -60px;
	width: 114px;
	height: 24px;
	left: 35%;
	cursor: pointer;
}
.savings-sprite-title {
	background-position:  -233px -60px;
	width: 164px;
	height: 24px;
	left: 30%;
}
.zoomplus:hover ~ .plusitem {
	-webkit-transform: scale(1.15);
	-moz-transform: scale(1.15);
	-o-transform: scale(1.15);
	-ms-transform: scale(1.15);
	transform: scale(1.15);
}
.zoomplus:active ~ .plusitem {
	-webkit-transform: scale(1);
	-moz-transform: scale(1);
	-o-transform: scale(1);
	-ms-transform: scale(1);
	transform: scale(1);
}

.blueline {
	background-color: #b8d9e1;
	position: absolute;
	top:47px;
	width: 100%;
	height: 1px;
}
.brownline {
	background-color: #a6989c;
	position: absolute;
	top:47px;
	width: 12px;
	height: 1px;
}
.columns {
	text-transform: uppercase;
	position: absolute;
	display: block;
	margin: auto;
	height: 390px;
}
#savebutton {
	position: absolute;
	left: 0; right: 0;
	display: block;
	cursor: pointer;
	width: 100%;
	height: 60px;
	bottom: 2%;
	overflow: hidden;
}
#savebutton:hover > #leftborder, #savebutton:hover > #rightborder, #savebutton:hover > #centerborder  {
	background-color: #fafcfc;
}
#savebutton:active > #leftborder, #savebutton:active > #rightborder, #savebutton:active > #centerborder  {
	background-color: #f3f7f8;
}

#leftborder, #rightborder, #centerborder  {
	border-top: 1px solid #b8d9e1;
	position: absolute;
	margin:auto;
	height: 100%;
	display: block;
	-moz-transition: 0.2s;
	-o-transition: 0.2s;
	-ms-transition: 0.2s;
	-webkit-transition: 0.2s;
	transition: 0.2s;
}
.saveaction {
	background-color: #eff6f8;
}

#leftborder {
	left: -21%; right: 490px;
	width: 340px;
}
#rightborder {
	left: 21%; right: -490px;
	width: 340px;
}
#centerborder {
	left: 0; right: 0;
	width: 40%;
}
#save {
	margin: auto;
	position: absolute;
	bottom:15px; left: 25px; right: 0;
	width: 138px;
	height: 24px;
	background-position: -400px -60px;
}

/* =============== SAVINGS SLIDER =============== */

#piggyicon {
	background-position: -100px 0;
	background-size: 538px 84px;
	position: absolute;
	display: block;
	width: 46px;
	height: 38px;
	left: 25px;
	top: 70px;
}
#topsavingsline {
	position: relative;
	display: block;
	width: 100%;
	height: 190px;
	border-bottom: 1px solid #e2e2e2;
}
#bottomsavingsline {
	position: relative;
	display: block;
	width: 100%;
	height: 92px;
	border-bottom: 1px solid #e2e2e2;
}
#savingsvalue{
	display: inline-block;
	border: 0px solid;
	background-color: transparent;
	position: absolute;
	top: 125px;
	left: 30%;
	font-family: "Museo-100";
	font-size: 38px;
	padding: 0;
}
#rublesign {
	cursor: pointer;
	background-size: 538px 84px;
	display: inline-block;
	width: 22px;
	height: 31px;
	position: relative;
	z-index: 1000;
}
#rublebox {
	top: 135px;
	width: 30%;
	height: 40px;
	left: 0;
	position: relative;
	display: inline-block;
}
#percentvalue{
	display: inline-block;
	border: 0px solid;
	position: relative;
	top: 48px;
	left: 125px;
	font-family: "Museo-300";
	font-size: 22px;
	color: #9e9e9e;
	background-color: white;
}

/* TOGGLES */
#deposit + label.button{
	position: absolute;
	top:16px;
}
#capitalization + label.button{
	position: absolute;
	bottom:-42px;
}
input#deposit, input#capitalization  {
	max-height: 0;
	max-width: 0;
	display: none;
}
input#deposit + label.button, input#capitalization + label.button{
	display: block;
	position: absolute;
	right:32px;
	box-shadow: inset 0 0 0px 1px #e3e3e3;
	height: 21px;
	width: 33px;
	border-radius: 15px;
}
input#deposit + label.button:before, input#capitalization + label.button:before {
	content: "";
	position: absolute;
	display: block;
	height: 21px;
	width: 21px;
	top: 0;
	left: 0;
	border-radius: 15px;
	-moz-transition: 0.2s ease-out;
	-o-transition: 0.2s ease-out;
	-ms-transition: 0.2s ease-out;
	-webkit-transition: 0.2s ease-out;
	transition: 0.2s ease-out;
}
input#deposit + label.button:after, input#capitalization + label.button:after {
	content: "";
	position: absolute;
	display: block;
	height: 21px;
	width: 21px;
	top: 0;
	left: 0px;
	border-radius: 15px;
	background: white;
	box-shadow: inset 0 0 0 1px #e0e0e0, 1px 1px 2px #ebebeb;
	-moz-transition: 0.2s ease-out;
	-o-transition: 0.2s ease-out;
	-ms-transition: 0.2s ease-out;
	-webkit-transition: 0.2s ease-out;
	transition: 0.2s ease-out;
}
/* END OF TOGGLES */

input#deposit:checked + label.button:before, input#capitalization:checked + label.button:before {
	width: 33px;
	height: 21px;
	background: #e7f6f8;
	box-shadow: inset 0 0 0px 1px #b4d6da;
}
input#deposit:checked + label.button:after, input#capitalization:checked + label.button:after {
	left: 13px;
	box-shadow: inset 0 0 0 1px #b4d6da, 1px 1px 1px #ebebeb;
}
#deposit:checked ~ .savingscapital, #deposit:checked ~ .savingspercent, #deposit:checked ~ input#percentvalue {
	color: #4b4b4b;
}
.savingstitle14 {
	font-family: "Museo-300";
	font-size: 14px;
	color: #4b4b4b;
	position: absolute;
	left: 30%;
	top: 70px;
}
.savingstitle12 {
	font-family: "Museo-300";
	font-size: 13px;
	color: #a2c1c6;
	font-style: italic;
	position: absolute;
	left: 30%;
	top: 94px;
}
.savingsdeposit {
	font-family: "Museo-300";
	font-size: 12px;
	color: #4b4b4b;
	position: absolute;
	left: 25px;
	top:20px;
}
.savingscapital, .savingspercent {
	font-family: "Museo-300";
	font-size: 12px;
	color: #b5b5b5;
	position: absolute;
}
.savingscapital {
	left: 25px;
	bottom:-40px;
}
.savingspercent {
	left: 25px;
	bottom:20px;
}

/* =============== INCOMES SLIDER =============== */
#noincomes, #noexpenses {
	width: 160px;
	height: 160px;
	position: absolute;
	display: block;
	top: 30%; left: 0; right: 0;
	margin: auto;
	cursor: pointer;
	z-index: 10;
}
.hoverplace {
	display: block;
	width: 100%;
	height: 100%;
}
.hoverplace:hover ~ .plusitemtitle, .majorplusitem:hover ~ .plusitemtitle, .plusitemtitle:hover {
	color: #a2c1c6;
}
.majorplusitem {
	top:0; bottom:0; left: 0; right: 0;
	margin: auto;
	position: absolute;
	display: block;
	width: 75px;
	height: 75px;
	-webkit-transition: 150ms;
	-moz-transition: 150ms;
	-o-transition: 150ms;
	-ms-transition: 150ms;
	transition: 150ms;
}
.majorplusitem:hover {
	-webkit-transform: scale(1.1);
	-moz-transform: scale(1.1);
	-o-transform: scale(1.1);
	-ms-transform: scale(1.1);
	transform: scale(1.1);
}
.majorplusitem:active {
	-webkit-transform: scale(1);
	-moz-transform: scale(1);
	-o-transform: scale(1);
	-ms-transform: scale(1);
	transform: scale(1);
}
.plusitemtitle {
	text-align: center;
	width: 100%;
	font-family: "Museo-300";
	font-size: 14px;
	color: #4b4b4b;
	position: absolute;
	bottom: 0;
	-webkit-transition: 0.25s;
	-moz-transition: 0.25s;
	-o-transition: 0.25s;
	-ms-transition: 0.25s;
	transition: 0.25s;
}
.plusitemitalic {
	text-align: center;
	width: 100%;
	font-family: "Museo-300";
	font-size: 13px;
	color: #a2c1c6;
	font-style: italic;
	position: absolute;
	top: 0;
}
.arrowup, .arrowdown {
	position: absolute;
	background-size: 538px 84px;
	width: 21px;
	height: 12px;
}
.arrowup {
	background-position: -30px 0;
}
.arrowdown {
	background-position: 0 0;
}
#incomeup, #incomedown {
	font-family: "Museo-300";
	font-size: 12px;
	color: #a2c1c6;
	font-style: italic;
	position: absolute;
	bottom: 0px;
	margin: auto;
	width: 90px;
	height: 12px;
	cursor: pointer;
	text-align: center;
}
#incomeup {
	left: 63%;
}
#incomedown {
	left: 35%;
}
#incomeslider {
	-webkit-transition: 0.25s;
	-moz-transition: 0.25s;
	-o-transition: 0.25s;
	-ms-transition: 0.25s;
	transition: 0.25s;
	position: absolute; /*RELATIVE!*/
	bottom: 0px;
	margin: auto;
	width: 100%;
}

/* =============== EXPENSE SLIDER =============== */

.plusitem {
	top: -8px; left: 9%;
	margin: auto;
	position: absolute;
	cursor: pointer;
	width: 33px;
	height: 33px;
	-webkit-border-radius: 75px;
	-moz-border-radius: 75px;
	border-radius: 75px;
	-webkit-transition: 150ms;
	-moz-transition: 150ms;
	-o-transition: 150ms;
	-ms-transition: 150ms;
	transition: 150ms;
}
.plusitemborder {
	position: absolute;
	border: 1px solid #aad6df;
	-webkit-border-radius: 75px;
	-moz-border-radius: 75px;
	border-radius: 75px;
	top:0; left: 0; right: 0; bottom: 0;
	margin: auto;
}
.plusitem:hover {
	-webkit-transform: scale(1.15);
	-moz-transform: scale(1.15);
	-o-transform: scale(1.15);
	-ms-transform: scale(1.15);
	transform: scale(1.15);
}
.plusitem:active {
	-webkit-transform: scale(1);
	-moz-transform: scale(1);
	-o-transform: scale(1);
	-ms-transform: scale(1);
	transform: scale(1);
}
.plusitemone, .plusitemtwo {
	position: absolute;
	top: 0; left: 0; right: 0; bottom: 0;
	margin: auto;
	background-color: #aad6df;
}
.plusitemone {
	width: 50%;
	height: 1px;
}
.plusitemtwo {
	width: 1px;
	height: 50%;
}

#expenseup, #expensedown {
	font-family: "Museo-300";
	font-size: 12px;
	color: #a2c1c6;
	font-style: italic;
	position: absolute;
	bottom:0px;
	margin: auto;
	width: 90px;
	height: 12px;
	cursor: pointer;
	text-align: center;
}
#expenseup {
	left: 63%;
}
#expensedown {
	left: 35%;
}
.frame {
	text-align: left;
	overflow: hidden;
	position: absolute;
	top:50px; left: 0; right: 0; bottom: 0;
	width: 100%;
	height: 284px;
}
.wrapper {
	position: absolute;
	top:0; left: 0; right: 0; bottom: 0;
	width: 100%;
	height: 100%;
}
#expenseslider {
	-webkit-transition: 0.25s;
	-moz-transition: 0.25s;
	-o-transition: 0.25s;
	-ms-transition: 0.25s;
	transition: 0.25s;
	display: none;
	position: absolute; /*RELATIVE!*/
	bottom: 0px;
	margin: auto;
	width: 100%;
}
.itembackground {
	display: block;
	position: relative;
	top: -26px;
	left: 25px;
}
.incomeitem, .expenseitem {
	-webkit-transition: 350ms ease-out;
	-moz-transition: 350ms ease-out;
	-o-transition: 350ms ease-out;
	-ms-transition: 350ms ease-out;
	transition: 350ms ease-out;
	background-position: 25px center;
	background-repeat: no-repeat;
	background-size: 42px 42px;
	border-bottom: 1px solid #e2e2e2;
	width: 100%;
	height: 70px;
	z-index: 500;
	cursor: pointer;
	overflow: hidden;
}
.incomeitem:hover, .expenseitem:hover {
	background-color: #fbfbfb;
}
.incomeitem:active, .expenseitem:active  {
	background-color: #f7f7f7;
}
.newitemadded {
	-webkit-animation: 4s newitemadded ease-out;
	-moz-animation: 4s newitemadded ease-out;
	-o-animation: 4s newitemadded ease-out;
	-ms-animation: 4s newitemadded ease-out;
	animation: 4s newitemadded ease-out;
}
.title11museo300 {
	font-family: "Museo-100";
	font-size: 14px;
	color: #676767;
	position: relative;
	left: 35%;
	top:12px;
}
.title9museo300 {
	font-family: "Museo-300";
	font-size: 9px;
	color: #676767;
	position: relative;
	left: 35%;
	top:20px;
}
.bolddigit20 {
	font-family: "Museo-500";
	font-size: 20px;
	color: #111;
}
.lightdigit20 {
	font-family: "Museo-100";
	font-size: 20px;
	color: #111;
}
.lighttitle20 {
	height: 40px;
	font-family: "Museo-100";
	font-size: 20px;
	color: #4b4b4b;
	position: absolute;
	left: 35%;
	cursor: pointer;
}

/* ITEMS AND FRAMES ANIMATION */
.sliderup {
	-webkit-transform: translateY(71px);
	-moz-transform: translateY(71px);
	-o-transform: translateY(71px);
	-ms-transform: translateY(71px);
	transform: translateY(71px);
}
.sliderdown {
	-webkit-transform: translateY(-71px);
	-moz-transform: translateY(-71px);
	-o-transform: translateY(-71px);
	-ms-transform: translateY(-71px);
	transform: translateY(-71px);
}
.endoflist {
	-webkit-animation: 0.5s endoflist ease-out;
	-moz-animation: 0.5s endoflist ease-out;
	-o-animation: 0.5s endoflist ease-out;
	-ms-animation: 0.5s endoflist ease-out;
	animation: 0.5s endoflist ease-out;
}
.startoflist {
	-webkit-animation: 0.5s startoflist ease-out;
	-moz-animation: 0.5s startoflist ease-out;
	-o-animation: 0.5s startoflist ease-out;
	-ms-animation: 0.5s startoflist ease-out;
	animation: 0.5s startoflist ease-out;
}
#expenseslider, #incomeslider {
	-webkit-animation: 1s frameanimate ease-out;
	-moz-animation: 0.8s frameanimate ease-out;
	-o-animation: 0.8s frameanimate ease-out;
	-ms-animation: 0.8s frameanimate ease-out;
	animation: 0.8s frameanimate ease-out;
}

/* NOTES WINDOW */

#add-notes {
	visibility: hidden;
	position: absolute;
	top: 0; left: 0; right: 0; bottom: 0;
	margin: auto;
	width: 465px;
	height: 530px;
	z-index: 2000;
	opacity: 1;
	-webkit-backface-visibility: hidden;
	-moz-backface-visibility: hidden;
	-o-backface-visibility: hidden;
	-ms-backface-visibility: hidden;
	backface-visibility: hidden;
	-webkit-perspective: 1300;
	-o-perspective: 1300px;
	-ms-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300;
}
#add-notes >.modal-content {
	height: 610px;
}
.notes-title {
	font-weight: 900;
	font-family: "Museo-500";
	font-size: 18px;
	color: #242424;
	position: absolute;
	width: 240px;
	height: 20px;
	margin: auto;
	right: 0; left: 0; top: 20px;
}
.notes-save {
	display: block;
	position: absolute;
	width: 100%;
	height: 42px;
	bottom: 20px;
	background-color: #cce5ec;
	cursor: pointer;
	line-height: 30px;
}
.notes-save:hover, .modal-save:hover {
	background-color: #d6ebf1;
}
.notes-save:active, .modal-save:active {
	background-color: #e0edf0;
}
.notes-input {
	line-height: 20px;
	display: none;
	resize: none;
	vertical-align: top;
	border: 1px solid #ccc;
	background-color: white;
	position: absolute;
	top: 78px; left: 0; right: 0;
	margin: auto;
	font-family: "Museo-300";
	font-size: 13px;
	padding: 20px;
	padding-top: 30px;
	width: 360px;
	height: 60%
}

/* MODAL WINDOWS */
#overlay {
	display: none;
	visibility: hidden;
	position: fixed;
	width: 100%;
	height: 100%;
	top: 0; left: 0;
	z-index: 1000;
	opacity: 0;
	background: rgba(0,0,0,0.65);
	-webkit-transition: all 0.3s;
	-o-transition: all 0.3s;
	-ms-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
}
#add-modal {
	visibility: hidden;
	position: absolute;
	top:50px; left: 0; right: 0; bottom: 0;
	margin: auto;
	width: 465px;
	height: 530px;
	z-index: 2000;
	opacity: 1;
	-webkit-backface-visibility: hidden;
	-moz-backface-visibility: hidden;
	-o-backface-visibility: hidden;
	-ms-backface-visibility: hidden;
	backface-visibility: hidden;
	-webkit-perspective: 1300px;
	-o-perspective: 1300px;
	-ms-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300px;
}
.modal-content {
	display: none;
	visibility: hidden;
	text-align: center;
	text-transform: uppercase;
	background: white;
	box-shadow: 0 0 15px rgba(0,0,0,0.2);
	position: relative;
	height: 480px;
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: rotateY(-60deg);
	-moz-transform: rotateY(-60deg);
	-ms-transform: rotateY(-60deg);
	transform: rotateY(-60deg);
	-webkit-transition: all 0.3s;
	-o-transition: all 0.3s;
	-moz-transition: all 0.3s;
	-ms-transition: all 0.3s;
	transition: all 0.3s;
	opacity: 0;
}

.modal-show {
	opacity: 1;
	visibility: visible;
}
.modal-show .modal-content {
	visibility: visible;
	-webkit-transform: rotateY(0deg);
	-moz-transform: rotateY(0deg);
	-ms-transform: rotateY(0deg);
	transform: rotateY(0deg);
	opacity: 1;
}
#overlay.modal-show {
	opacity: 1;
	visibility: visible;
}
.close-sign {
	background-position:  0 -22px;
	background-size: 538px 84px;
	position: absolute;
	width: 16px;
	height: 16px;
	top: 20px; right: 26px;
}
.modal-close {
	position: absolute;
	width: 86px;
	height: 62px;
	top: 0; right: 0;
	cursor: pointer;
	z-index: 3500;
}
.modal-title {
	font-weight: 900;
	font-family: "Museo-500";
	font-size: 18px;
	color: #242424;
	position: absolute;
	width: 240px;
	height: 20px;
	margin: auto;
	right: 0; left: 0; top: 20px;
}
.modal-save {
	display: block;
	position: absolute;
	width: 100%;
	height: 42px;
	top: 415px;
	background-color: #cce5ec;
	cursor: pointer;
	line-height: 30px;
}
.modal-save-icon {
	background-position: -60px 0;
	background-size: 538px 84px;
	position: absolute;
	width: 30px;
	height: 30px;
	left: 32%; top: 6px;
}
.modal-save-text {
	position: absolute;
	display: inline-block;
	margin: auto;
	top:0; bottom:0; left: 32%;
	width: 210px;
	height: 30px;
	font-family: "Museo-500";
	vertical-align: middle;
	font-size: 18px;
	color: white;
}
.modal-delete {
	-webkit-transition: 0.2s ease-out;
	-moz-transition: 0.2s ease-out;
	-ms-transition: 0.2s ease-out;
	-o-transition: 0.2s ease-out;
	display: none;
	position: absolute;
	width: 56px;
	height: 42px;
	top: 415px; right: 0;
	background-color: #d9ebf0;
	border-left: 2px solid white;
	cursor: pointer;
	line-height: 30px;
	overflow: hidden;
}
.modal-delete:hover {
	width: 380px;
	background-color: #facece;
}
.modal-delete:active {
	background-color: #ffe3e3;
}
#modaldeletecross {
	position: absolute;
	width: 30px;
	height: 30px;
	background-position: -320px 0;
	margin-top: 6px;
	margin-left: 13px;
}
.modal-delete-text {
	background-position: -320px 0;
	position: absolute;
	display: inline-block;
	margin: auto;
	top:0; bottom:0; left: 13px;
	width: 190px;
	height: 30px;
	font-family: "Museo-500";
	vertical-align: middle;
	font-size: 18px;
	color: white;
}
.modalvalue {
	text-align: center;
	display: none;
	border: 0px solid;
	background-color: transparent;
	position: absolute;
	top: 78px; left: 0; right: 0;
	margin: auto;
	font-family: "Museo-500";
	font-size: 86px;
	padding: 0;
	width: 370px;
	-webkit-transition: 0.3s;
	-moz-transition: 0.3s;
	-ms-transition: 0.3s;
	-o-transition: 0.3s;
}
.modalvalueerror {
	color: #ffdd33;
	-webkit-animation: 0.5s modalvalueerror ease-out;
	-moz-animation: 0.5s modalvalueerror ease-out;
	-o-animation: 0.5s modalvalueerror ease-out;
	-ms-animation: 0.5s modalvalueerror ease-out;
	animation: 0.5s modalvalueerror ease-out;
}
.modaltitle {
	display: none;
	text-transform: uppercase;
	position: absolute;
	top: 345px; left: 0; right: 0;
	margin: auto;
	text-align: center;
	border: 1px solid #ccc;
	color: #4c4c4c;
	font-family: "Museo-300", Arial;
	font-size: 14px;
	height: 30px;
	width: 296px;
	letter-spacing: 1px;
	-webkit-transition: all 0.4s;
	-o-transition: all 0.4s;
	-ms-transition: all 0.4s;
	-moz-transition: all 0.4s;
	transition: all 0.4s;
}
.modaltitleerror {
	background-color: #ffdd33;
}
.modalselects {
	z-index: 2000;
	text-transform: lowercase;
	text-align: left;
	display: block;
	position: absolute;
	top: 200px; left: 0; right: 0;
	margin: auto;
	width: 260px;
	height: 30px;
}
* {
	margin: 0;
	padding: 0;
}
.modalselects .selectbox {
	color: #333;
	vertical-align: middle;
	cursor: pointer;
	margin: 5px;
}
.modalselects .selectbox .select {
	width: 60px;
	height: 24px;
	padding: 0 45px 0 10px;
	font: 12px/24px Arial;
	border: 1px solid #ccc;
}
.modalselects .selectbox .select .text {
	display: block;
	width: 100%;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow: hidden;
}
.modalselects .selectbox .trigger .arrow {
	position: absolute;
	top: 11px;
	right: 10px;
	border-left: 3px solid transparent;
	border-right: 3px solid transparent;
	border-top: 3px solid #a1a1a1;
	width: 0;
	height: 0;
	overflow: hidden;
}
.modalselects .selectbox .dropdown {
	top: 25px;
	width: 115px;
	margin: 0;
	padding: 0 0;
	background: #FFF;
	border: 1px solid #ccc;
	font: 12px Arial;
}

.initicons-arrow {
	background-position: -32px -24px;
	background-size: 538px 84px;
	position: absolute;
	width: 15px;
	height: 9px;
	right: 0; top: 18px;
}
.initicons {
	cursor: pointer;
	width: 75px;
	height: 42px;
	position: absolute;
	text-align: left;
	top: 270px; left: 0; right: 0;
	margin: auto;
}
.initicons img {
	width: 42px;
	height: 42px;
}
.initicons:hover {
	opacity: 0.8;
}
.initicons:active {
	-webkit-transform: scale(0.92);
	-moz-transform: scale(0.92);
	-o-transform: scale(0.92);
	-ms-transform: scale(0.92);
	transform: scale(0.92);
}
.modalincomessurface {
	position: absolute;
	z-index: 3000;
	position: absolute;
	width: 100%;
	height: 100%;
	background-color: white;
	display: none;
}
.modalexpensessurface {
	z-index: 3000;
	position: absolute;
	width: 100%;
	height: 100%;
	background-color: white;
	display: none;
}
#modalexpensetable {
	text-align: center;
	background-color: white;
	position: absolute;
	top: 14%; left: 42px;

}
#modalincomestable {
	text-align: center;
	background-color: white;
	position: absolute;
	top: 30%; left: 42px;
}
.modaltable tr, .modaltable-low tr {
	background-color: #ddeef1;
}
.modaltable td, .modaltable-low td {
	cursor: pointer;
	width: 86px;
	height: 86px;
}
.imgbox {
	background-color: white;
	border: 2px solid white;
	-webkit-transition: all 0.1s;
	-o-transition: all 0.1s;
	-ms-transition: all 0.1s;
	-moz-transition: all 0.1s;
	transition: all 0.1s;
	width: 86px;
	height: 86px;
}
.imgbox:hover {
	border: 2px solid #ddeef1;
}
.modalborderwhite {
	border: 2px solid white;
}
.iconbox {
	background-color: white;
	position: absolute;
	margin:22px;
}
.auto {background-position: -989px 0;}
.gas {background-position: -602px 0;}
.home {background-position: -473px 0;}
.baby {background-position: -946px 0;}

.cart {background-position: -903px 0;}
.clothes {background-position: -817px 0;}
.phone {background-position: -258px 0;}
.utilities {background-position: -43px 0;}

.island {background-position: -430px 0;}
.earth {background-position: -731px 0;}
.meal {background-position: -387px 0;}
.sport {background-position: -129px 0;}

.medical {background-position: -344px 0;}
.tv {background-position: -86px 0;}
.smoking {background-position: -172px 0;}
.other {background-position: -301px 0;}

.edu {background-position: -688px 0;}
.graphs {background-position: -516px 0;}
.wallet {background-position: 0 0;}
.case {background-position: -860px 0;}

.rub {background-position: -215px 0;}
.euro {background-position: -645px 0;}
.doll {background-position: -774px 0;}
.gbp {background-position: -559px 0;}

#chooseicon {
	position: absolute;
	left: 0; top: 0;
}

.imgbox:active {
	-webkit-transform: scale(0.8);
	-moz-transform: scale(0.8);
	-o-transform: scale(0.8);
	-ms-transform: scale(0.8);
	transform: scale(0.8);
}
.modalforward {
	-webkit-animation: 0.4s modalforward ease-out;
	-moz-animation: 0.4s modalforward ease-out;
	-o-animation: 0.4s modalforward ease-out;
	-ms-animation: 0.4s modalforward ease-out;
	animation: 0.4s modalforward ease-out;
}
.modalreverse {
	-webkit-animation: 0.3s modalreverse ease-out;
	-moz-animation: 0.5s modalreverse ease-out;
	-o-animation: 0.5s modalreverse ease-out;
	-ms-animation: 0.5s modalreverse ease-out;
	animation: 0.3s modalreverse ease-out;
}

/* ============= STATISTIC PAGE STYLES =============*/

/* MAIN BLOCK */
#mainblock {
	-moz-transition: 0.3s ease-out;
	-o-transition: 0.3s ease-out;
	-ms-transition: 0.3s ease-out;
	-webkit-transition: 0.3s ease-out;
	transition: 0.3s ease-out;
	width: 1370px;
	height: 680px;
	position: absolute;
	margin: auto;
	left:0;	right:0; top:22%;
}
.flag {
	height: 19px;
	border: 1px solid #c7dade;
	font-family: "Museo-100";
	font-size: 11px;
	color: #242424;
	text-transform: uppercase;
	font-style: italic;
	line-height: 20px;
	padding-left: 20px;
	left: 0;
}
#deltatitle {
	position: absolute;
	top: -10px;
	width: 130px;
}
#savingstitle {
	position: absolute;
	bottom: 240px;
	width: 90px;
}
.triangle {
	position: absolute;
	bottom: -14px;
	left: -1px;
	width: 15px;
	height: 13px;
	background-position: -523px 0;
}
/* SAVINGS CHART */
#savingschart {
	position: absolute;
	width: 504px;
	height: 222px;
	bottom: 50px;
	right: 0;
}
#horizontal, #chartline {
	position: absolute;
}
#month0 {
	position: absolute;
	left:0;
	bottom: 0;
	display: block;
	margin-right: -4px;
	width: 0;
	height: 68px;
	border-left: 1px solid #cdc6c6;
}
#month0 .small-month-circle, #month0 .month-name {
	display: block;
}
#month0 .month-name {
	bottom: 32%;
}
#month12 .month-name {
	width: 20px;
	height: 16px;
}
.months {
	position: relative;
	display: inline-block;
	margin-right: -4px;
	width: 42px;
	height: 100%;
}
.in-month {
	position: absolute;
	bottom: 0;
	width: 100%;
	height: 50%;
}
.small-month-circle {
	position: absolute;
	right: -5px;
	top: -4px;
	width: 7px;
	height: 7px;
	border: 1px solid #b9b2b4;
	border-radius: 20px;
	background-color: white;
}
.large-month-circle {
	position: absolute;
	right: -10px;
	top: -10px;
	width: 17px;
	height: 17px;
	border: 1px solid #b9b2b4;
	border-radius: 20px;
	background-color: white;
	display: block;
}
.bluedot {
	position: absolute;
	right: 3px;
	top: 3px;
	width: 11px;
	height: 11px;
	border-radius: 20px;
	background-color: #d5e4e7;
}
.large-month-val {
	text-transform: uppercase;
	text-align: right;
	position: absolute;
	top: -34px; right: 5px;
	width: 160px;
	height: 20px;
	font-family: "Museo-500";
	font-size: 22px;
	color: #333;
}
.large-month-val .curr {
	font-family: "Museo-100";
	font-size: 12px;
}
.month-val {
	text-transform: uppercase;
	text-align: center;
	position: absolute;
	bottom: -32px; left: -18px;
	width: 120px;
	height: 14px;
	font-family: "Museo-300";
	font-size: 15px;
	color: #333;
	display: none;
	background-color: white;
}
.month-val .curr {
	font-family: "Museo-100";
	font-size: 10px;
}
.month-name {
	position: absolute;
	bottom: 40%; right: -11px;
	font-family: "Museo-300";
	text-transform: uppercase;
	text-align: center;
	font-size: 10px;
	color: #948b8e;
	background-color: white;
	height: 21px;
	width: 25px;
	line-height: 21px;
	display: none;
}
#month6, #month12{
	border-right: 1px solid #cdc6c6;
}
#month6 .small-month-circle, #month6 .month-name, #month12 .month-name {
	display: block;
}
.months:hover .in-month {
	border-right: 1px solid #cdc6c6;
}
.months:hover .small-month-circle,  .months:hover .month-name, .months:hover .month-val  {
	display: block;
}
/* SAVINGS SLIDER */
#savings-slider-container {
	width: 260px;
	height: 50px;
	position: absolute;
	bottom: 70px; left: 40px;
}
.savings-slider {
	text-transform: uppercase;
	position: absolute;
	top: -90px;
	font-family: "Museo-300";
	font-size: 11px;
	color: #5e5e5e;
}
#savingsTip0, #savingsTip100 {
	position: absolute;
	width: 100%;
	height: 35px;
	font-family: "Museo-300";
	font-style: italic;
	font-size: 11px;
	color: #a59b9e;
	display: none;
}
#savingsTip0 {
	bottom: -5px; left: 38px;
}
#savingsTip100 {
	bottom: -5px;
}
.noUi-target,.noUi-target *
{
	-webkit-touch-callout:none;
	-webkit-user-select:none;
	-ms-touch-action:none;
	-ms-user-select:none;
	-moz-user-select:none;
	-moz-box-sizing:border-box;
	box-sizing:border-box
}
.noUi-base {
	width:100%;
	height:100%;
	position:absolute;
}
.noUi-origin {
	position:absolute;
	right:0;
	top:0;
}
.noUi-handle {
	content: "";
	position:relative;
	z-index:1;
	border: 1px solid #c4d5d9;
	cursor:default;
	-webkit-border-radius: 23px;
	-ms-border-radius: 23px;
	-o-border-radius: 23px;
	-moz-border-radius: 23px;
	border-radius: 23px;
	background-position: -516px -17px;
}
.noUi-handle-upper {
	width: 3px;
}
.noUi-stacking .noUi-handle {
	z-index:10
}

.noUi-stacking+.noUi-origin {
	z-index:-1
}
.noUi-state-tap .noUi-origin {
	-webkit-transition:left .3s,top .3s;
	transition:left .3s,top .3s
}
.noUi-state-drag * {
	cursor:inherit!important
}
.noUi-horizontal {
	height: 4px
}
.noUi-horizontal .noUi-handle {
	width:23px;
	height:23px;
	left:-12px;
	top:-9px
}
.noUi-background {
	background:#d9e7ea;
	border-left: 2px solid #a39a9d;
	border-right: 2px solid #a39a9d;
}
.noUi-dragable
{
	cursor: w-resize
}
.noUi-vertical .noUi-dragable {
	cursor:n-resize;
}
.noUi-active {
	border: 1px solid #95b4b8;
}
.noUi-handle:after {
	content: attr(percent);
	text-align: center;
	display:block;
	position:absolute;
	width: 30px; height: 30px;
	left: 4px; top: -38px;
	font-family: "Museo-300";
	font-size: 11px;
	color: #2f2f2f;
	background-position: -414px 0;
	line-height: 18px;
}
.noUi-handle:before {
	content: attr(value);
	text-align: center;
	display:block;
	position:absolute;
	height:1px;
	width:180px;
	height: 15px;
	left: -80px; top: 35px;
	font-family: "Museo-100";
	font-size: 16px;
	color: #2f2f2f;
}
[disabled] .noUi-connect,[disabled].noUi-connect {
	background:#B8B8B8
}
[disabled] .noUi-handle {
	cursor:not-allowed
}
/* SAVINGS CIRCLE */
#savingscircles {
	text-align: center;
	width: 385px;
	height: 385px;
	position: absolute;
	left: 390px; bottom: 30px;
	z-index: 800;
}
#after-savings, #before-savings {
	border: 1px solid #c9dadd;
	-webkit-border-radius: 350px;
	-ms-border-radius: 350px;
	-o-border-radius: 350px;
	-moz-border-radius: 350px;
	border-radius: 350px;
}
#after-savings {
	width: 82%;
	height: 82%;
	position: absolute;
	right:0; top:0;
}
#before-savings {
	width: 46%;
	height: 46%;
	position: absolute;
	left:0; bottom:0;
}
.savings-circle-title {
	font-size: 12px;
	position: absolute;
	margin: auto;
	top: 30%; left:0; right:0;
}
.savings-circle-currency {
	font-size: 11px;
	position: absolute;
	margin: auto;
	bottom: 22%; left:0; right:0;
}
#before-savings-value {
	position: absolute;
	width: 130%;
	height: 100%;
	margin: auto;
	left:-15%; right: 0;
	text-align: center;
	line-height: 165px;
	font-size: 30px;
	top: 8%;
}
#after-savings-value {
	width: 130%;
	height: 100%;
	position: absolute;
	margin: auto;
	left:-15%; right: 0;
	top:7%;
	text-align: center;
	line-height: 290px;
}
/* LINES CONTAINER */
#incomes-lines-container, #expenses-lines-container {
	-moz-transition: 0.3s ease-out;
	-o-transition: 0.3s ease-out;
	-ms-transition: 0.3s ease-out;
	-webkit-transition: 0.3s ease-out;
	transition: 0.3s ease-out;
	background-color: white;
	width: 270px;
	height: 300px;
	position: absolute;
	left: 375px; top: 0;
	z-index: 200;
	padding-top: 65px;
	padding-left: 30px;
}
#incomes-lines-container {
	display: none;
}
.lines-title {
	cursor: pointer;
	position: absolute;
	width: 400px;
	top: 35px;
	text-transform: uppercase;
	font-family: "Museo-300";
	font-size: 13px;
	color: black;
}
.lineitemtitle {
	position: absolute;
	top: 15px;
	width: 280px;
	height: 70px;
}
.lineitemvalue {
	font-family: "Museo-300";
	font-size: 25px;
	position: absolute;
	top: 15px;
	left: 64px; top:50px;
	width: 180px;
}
.lineitemcurr {
	font-size: 11px;
}
.lineitempercent {
	font-family: "Museo-500";
	font-size: 10px;
	color: #928588;
	position: absolute;
	top: -8px;
	left: -27px;
}
.grey {
	color: #adadad;
}
.greysmall {
	font-size: 9px;
}
.itemline {
	-moz-transition: 0.5s ease-out;
	-o-transition: 0.5s ease-out;
	-ms-transition: 0.5s ease-out;
	-webkit-transition: 0.5s ease-out;
	transition: 0.5s ease-out;
	font-size: 13px;
	cursor: pointer;
	position: relative;
	height: 9px;
	border-top: 2px solid #d5e4e7;
	overflow: hidden;
	background-color: white;
	width: 1%;
}
.itemlinebackground {
	position: absolute;
	top: 36px; left:0;
	width: 42px;
	height: 42px;
}
.leftpoint {
	width: 2px;
	height: 2px;
	background-color: #a39a9d;
	position: absolute;
	top:-2px; left:0;
}
.activeline {
	border-top: 4px solid #a39a9d;
	height: 88px;
	overflow: visible;
}
/* LINES CURSOR */
#expense-cursor {
	-webkit-transform: rotate(68deg);
	-moz-transform: rotate(68deg);
	-ms-transform: rotate(68deg);
	-o-transform: rotate(68deg);
	transform: rotate(68deg);
	width: 310px;
	height: 310px;
	position: absolute;
	left: 225px; top: -106px;
	z-index: 100;
	display: none;
	cursor: pointer;
}
#incomes-cursor {
	-webkit-transform: rotate(52deg);
	-moz-transform: rotate(52deg);
	-ms-transform: rotate(52deg);
	-o-transform: rotate(52deg);
	transform: rotate(52deg);
	width: 370px;
	height: 370px;
	position: absolute;
	left: 227px; top: -120px;
	z-index: 100;
	display: none;
	cursor: pointer;
}
.cursorline {
	width: 1px;
	height: 50%;
	position: absolute;
	bottom: 0; left: 149px;
	background-color: #727272;
}
.cursorpoint {
	position: absolute;
	bottom: -3px; left: 147px;
	width: 6px;
	height: 6px;
	border-radius: 10px;
	background-color: #727272;
}
/* LARGE CIRCLE */
#outermaindiv  {
	color: black;
	position: absolute;
	width: 265px;
	height: 265px;
	position: absolute;
	top: 50px; left:10px;
	z-index: 0;
	cursor: pointer;
}
#innermaindiv  {
	position: absolute;
	width: 100%;
	height: 100%;
	top:0; left:0;
	margin: 21px;
}
#outermaincursordiv  {
	position: absolute;
	width: 100%;
	height: 100%;
	top:0;
	z-index: 500;
	margin: -19px;
}
.linesbackground {
	position: absolute;
	width: 100%;
	height: 100%;
	background-image: url("../images/linesbackground.png");
	background-repeat: repeat;
}
.topmaincircletitle {
	width: 100px;
	height: 30px;
	text-align: center;
	position: absolute;
	margin: auto;
	left: 0; right: 0; top:84px;
	font-size: 15px;
	font-style: italic;
}
.bottommaincircletitle {
	width: 100px;
	height: 30px;
	text-align: center;
	position: absolute;
	margin: auto;
	left: 0; right: 0; bottom:60px;
	font-size: 13px;
}
#outer-circle-value {
	width: 100%;
	height: 100%;
	text-align: center;
	position: absolute;
	margin: auto;
	line-height: 265px;
	top: 5px;
	font-size: 48px;
}
.lightcircletitle {
	font-family: "Museo-100";
	text-transform: uppercase;
}
.boldcircletitle {
	font-family: "Museo-500";
	text-transform: uppercase;
}
#maincircle100percent {
	width: 30px;
	height: 15px;
	position: absolute;
	top: 50px; right: 100px;
	font-size: 12px;
}
#maincircleline {
	width: 1px;
	height: 27px;
	position: absolute;
	top: 17px; right: 131px;
	background-color: #898989;
	box-shadow: -1px 0 1px #acacac;
}
#outer-circle-percent {
	display: none;
	width: 30px;
	height: 30px;
	position: absolute;
	left: 0; right: 0; top: 0;
	font-size: 11px;
	z-index: 1000;
}
/* PENDANTS */
#firstpendant {
	overflow: visible;
	z-index: -100;
	position: absolute;
	bottom: 0; left:60px;
	width: 60px;
	height: 100px;
}
#firstpendant > .pendant-circle {
	bottom: 77px;
	border: 2px solid #d3d8ce;
}
#firstpendant > .pendantline {
	bottom: 90px;
	background-color: #d3d8ce;
}
#firstpendant > .pendantfont {
	bottom: 50px;
}
#secondpendant {
	overflow: visible;
	z-index: -100;
	position: absolute;
	bottom: 0; left:282px;
	width: 45px;
	height: 100px;
}
#secondpendant > .pendant-circle {
	bottom: 57px;
	border: 2px solid #b9b2b4;
}
#secondpendant > .pendantline {
	bottom: 70px;
	background-color: #b9b2b4;
}
#secondpendant > .pendantfont {
	bottom: 30px;
}
#thirdpendant {
	overflow: visible;
	z-index: -100;
	position: absolute;
	bottom: 0; right:60px;
	width: 45px;
	height: 100px;
}
#thirdpendant > .pendant-circle {
	bottom: 37px;
	border: 2px solid #abb1bf;
}
#thirdpendant > .pendantline {
	bottom: 50px;
	background-color: #abb1bf;
}
#thirdpendant > .pendantfont {
	bottom: 10px;
}
.pendant-circle {
	position: absolute;
	left: 17px;
	width: 8px;
	height: 8px;
	border-radius: 20px;
}
.pendantfont {
	position: absolute;
	text-align: center;
	width: 70px;
	font-size: 11px;
	font-style: italic;
	left: -12px;
}
.pendantline {
	position: absolute;
	left: 22px;
	width: 1px;
	height: 120%;
}
/* SMALL CIRCLES */
#movingcircle-1, #movingcircle-2, #movingcircle-3 {
	-webkit-animation: 1s spincircle ease-out infinite;
	-moz-animation: 1s spincircle ease-out infinite;
	-o-animation: 1s spincircle ease-out infinite;
	-ms-animation: 1s spincircle ease-out infinite;
	animation: 1s spincircle ease-out infinite;
}
.flippedcard {
	-webkit-transform: rotateY(-180deg);
	-moz-transform: rotateY(-180deg);
	-ms-transform: rotateY(-180deg);
	-o-transform: rotateY(-180deg);
	transform: rotateY(-180deg);
}
.flippedcardinfo {
	-webkit-transform: rotateY(180deg);
	-moz-transform: rotateY(180deg);
	-ms-transform: rotateY(180deg);
	-o-transform: rotateY(180deg);
	transform: rotateY(180deg);
}
#small-circles-container {
	position: absolute;
	right: 0; top: 40px;
	width: 608px;
	height: 290px;
	overflow: visible;
}
#firstcirclediv, #secondcirclediv, #thirdcirclediv {
	-webkit-perspective: 1000;
	-moz-perspective: 1000px;
	-ms-perspective: 1000px;
	-o-perspective: 1000px;
	perspective: 1000;
	-moz-transition: 0.3s ease-out;
	-o-transition: 0.3s ease-out;
	-ms-transition: 0.3s ease-out;
	-webkit-transition: 0.3s ease-out;
	transition: 0.3s ease-out;
	cursor: pointer;
	position: relative;
	top: 0;
	width: 200px;
	height: 180px;
	display: inline-block;
	background-color: white;
}
/* Backfaces */

.circlesselect {
	z-index: 2000;
	text-transform: uppercase;
	text-align: center;
	display: block;
	position: absolute;
	top: 94px; left: 0; right: 20px;
	margin: auto;
	width: 136px;
	height: 80px;
}
.circlesselect > .selectbox .select {
	position: absolute;
	margin: auto;
	width: 136px;
	height: 22px;
	padding: 0 10px 0 10px;
	font: 10px/23px "Museo-500";
	border: 1px solid #ccc;
}
.circlesselect > .selectbox .dropdown {
	top: 23px;
	width: 156px;
	max-height: 220px;
	margin: 0;
	padding: 0 0;
	background: #FFF;
	border: 1px solid #ccc;
	font-family: "Museo-300";
	font-size: 10px;
}





#circle-select-1-back, #circle-select-2-back, #circle-select-3-back  {
	position: absolute;
	margin: auto;
	left: 0; right: 0; top: 30px;
	width: 42px;
	height: 42px;
}
.flippedcircle {
	-webkit-transform: rotateY(-180deg);
	-moz-transform: rotateY(-180deg);
	-ms-transform: rotateY(-180deg);
	-o-transform: rotateY(-180deg);
	transform: rotateY(-180deg);
}
.frontcircle, .backcircle {
	-webkit-backface-visibility: hidden;
	-moz-backface-visibility: hidden;
	-ms-backface-visibility: hidden;
	-o-backface-visibility: hidden;
	backface-visibility: hidden;
	overflow: visible;
	position: absolute;
}
.frontcircle {
	-moz-transition: 0.3s ease-out;
	-o-transition: 0.3s ease-out;
	-ms-transition: 0.3s ease-out;
	-webkit-transition: 0.3s ease-out;
	transition: 0.3s ease-out;
	position: absolute;
	margin: auto;
	right: 0; left: 0;
	z-index: 2;
	width: 165px;
	height: 165px;
}
.backcircle {
	-webkit-transform: rotateY(180deg);
	-moz-transform: rotateY(180deg);
	-ms-transform: rotateY(180deg);
	-o-transform: rotateY(180deg);
	transform: rotateY(180deg);
	z-index: 1;
	position: absolute;
	top: -30px;
	left: 0; right: 0;
	width: 200px;
	height: 200px;
}
.backcircle .circletoptitle {
	width: 170px;
	height: 50px;
	line-height: 14px;
	bottom: -85px;
}
#firstcirclediv {
	left: -16px;
}
#secondcirclediv {
	left: 0;
}
#thirdcirclediv {
	left: 16px;
}
#firstcircledivflipper, #secondcircledivflipper, #thirdcircledivflipper {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	-ms-transform-style: preserve-3d;
	-o-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transition: 1000ms;
	-moz-transition: 1000ms;
	-ms-transition: 1000ms;
	-o-transition: 1000ms;
	transition: 1000ms;
	position: relative;
	overflow: visible;
}
.frontcircle:active {
	-webkit-transform: scale(0.8);
	-moz-transform: scale(0.8);
	-o-transform: scale(0.8);
	-ms-transform: scale(0.8);
	transform: scale(0.8);
}
.cursordiv  {
	position: absolute;
	width: 100%;
	height: 100%;
	top: 0;
	z-index: 600;
	margin: -12px;
}
.circletoptitle  {
	-moz-transition: 0.3s ease-out;
	-o-transition: 0.3s ease-out;
	-ms-transition: 0.3s ease-out;
	-webkit-transition: 0.3s ease-out;
	transition: 0.3s ease-out;
	text-align: center;
	overflow: hidden;
	font-style: italic;
	font-size: 10px;
	position: absolute;
	width: 120px;
	height: 12px;
	margin: auto;
	left: 0; right: 0; top: 52px;
}
.circlevalue {
	position: absolute;
	width: 100%;
	height: 100%;
	top: 4px;
	text-align: center;
	line-height: 165px;
	font-size: 31px;
}
.bottomcircletitle {
	width: 100px;
	height: 30px;
	text-align: center;
	position: absolute;
	margin: auto;
	left: 0; right: 0; top: 110px;
	font-size: 10px;
}
#first-circle-percent, #second-circle-percent, #third-circle-percent {
	display: none;
	width: 30px;
	height: 30px;
	position: absolute;
	left: 0; right: 0; top: 0;
	font-size: 11px;
}
.circle100percent {
	width: 30px;
	height: 15px;
	position: absolute;
	top: 30px; right: 52px;
	font-size: 9px;
}
.circleline {
	width: 1px;
	height: 17px;
	position: absolute;
	top: 11px;
	right: 82px;
	background-color: #898989;
}
#setcurrency {
	right: -18px;
	top: -15%;
	position: absolute;
	width: 170px;
	height: 42px;
}
#rubcurr, #eurcurr, #usdcurr {
	vertical-align: top;
	text-align: center;
	position: relative;
	font-size: 11px;
	text-transform: uppercase;
	color: #444;
	display: inline-block;
	width: 42px;
	height: 42px;
	border-radius: 42px;
	margin-right: 7px;
	line-height: 43px;
}
#rubcurr:hover, #eurcurr:hover, #usdcurr:hover {
	border: 2px solid #f6f6f6;
}
.currunchecked {
	cursor: pointer;
	font-family: "Museo-100";
	border: 2px solid white;
}
.currchecked {
	cursor: default;
	font-family: "Museo-500";
	border: 2px solid #e8e8e8;
}

/* ============== CONDITIONS FOR DIFFERENT SCREEN SIZES ============== */
@media screen and (max-height: 870px) {
	#mainblock {
		height: 620px; top:19%;
	}
	#savingschart {
		bottom: 10px;
	}
	#savingscircles {
		bottom: 0px;
	}
	#savings-slider-container {
		bottom: 20px;
	}
	#savingstitle {
		bottom: 190px;
	}
	#small-circles-container {
		height: 274px;
	}

}
@media screen and (max-height: 780px) {
	#mainblock {
		height: 590px; top:17%;
	}
	#savingschart {
		bottom: 20px;
	}
	#savingscircles {
		bottom: 25px;
	}
	#savings-slider-container {
		bottom: 30px;
	}
	#savingstitle {
		bottom: 200px;
	}
	#logo_statistic {
		top: -25px;
		-webkit-transform: rotateY(180deg) scale(0.8);
		-moz-transform: rotateY(180deg) scale(0.8);
		-ms-transform: rotateY(180deg) scale(0.8);
		-o-transform: rotateY(180deg) scale(0.8);
		transform: rotateY(180deg) scale(0.8);
	}
	#small-circles-container {
		height: 274px;
	}
	#setcurrency {
		top: -12%;
	}
	#infopage {
		height: 610px;
		margin-top: -70px;
	}
	#infosubtitle {
		top: 40px;
	}
	#infotitle {
		top: 75px;
	}
}
@media screen and (max-height: 700px) {
	.month-val {
		bottom: 5px;
	}
	#mainblock {
		height: 582px; top:14%;
	}
	#savingschart {
		bottom: 20px;
	}
	#savingscircles {
		bottom: 10px;
	}
	#savings-slider-container {
		bottom: 30px;
	}
	#savingstitle {
		bottom: 200px;
	}
	#logo_statistic {
		top: -35px;
		-webkit-transform: rotateY(180deg) scale(0.7);
		-moz-transform: rotateY(180deg) scale(0.7);
		-ms-transform: rotateY(180deg) scale(0.7);
		-o-transform: rotateY(180deg) scale(0.7);
		transform: rotateY(180deg) scale(0.7);
	}
	#small-circles-container {
		height: 270px;
	}
	#setcurrency {
		top: -10%;
	}
}

@media screen and (max-width: 1100px) {
	.columns {
		width: 300px; top:24%;
	}
	#savings {
		left: 20%; right: -450px; bottom: 0;
	}
	#incomes {
		left: -20%; right: 450px; bottom: 0;
	}
	#expenses {
		left: 0; right: 0; bottom: 0;
	}
}
@media screen and (min-width: 1100px) {
	.columns {
		width: 340px; top:24%;
	}
	#savings {
		left: 21%; right: -490px; bottom: 0;
	}
	#incomes {
		left: -21%; right: 490px; bottom: 0;
	}
	#expenses {
		left: 0; right: 0; bottom: 0;
	}
}
@media screen and (max-height: 850px) {
	#logo_greeting, #logo_settings {
		background: url("../images/logo_large.gif") no-repeat;
		background-position: top center;
		background-size: 137px 204px;
		z-index: 1000;
		width: 172px;
		height: 204px;
		top: 5%;
	}
	#settings_hat {
		height: 28%;
	}
	.columns {
		top:16%;
	}
	#logo_settings {
		height: 130px;
		top: 8%;
	}
	#savebutton {
		bottom: 3%;
	}
	#incomeup, #incomedown, #expenseup, #expensedown {
		bottom: 20px;
	}
}
@media screen and (max-height: 700px) {
	#settings_hat {
		height: 22%;
	}
	#add-notes >.modal-content {
		height: 530px;
	}
	.notes-input {
		height: 56%
	}
	#logo_greeting, #logo_settings {
		background: url("../images/logo.gif") no-repeat;
		background-size: 114px 145px;
		width: 114px;
		height: 145px;
		top: 8%;
	}
	.columns {
		top:16%;
	}
	#logo_settings {
		height: 100px;
	}
	#bubble {
		right: -70px;
	}
	#savebutton {
		bottom: 1%;
	}
	#incomeup, #incomedown, #expenseup, #expensedown {
		bottom: 20px;
	}
	#piggy {
		background: url("../images/piggy.gif") no-repeat;
		background-size: 149px 149px;
		width: 149px;
		height: 149px;
	}
	#logotext {
		background: url("../images/logotext.gif") no-repeat;
		size: 163px 67px;
		width: 163px;
		height: 67px;
		margin-top: 24px;
	}
	#wrapper {
		top: 305px;
	}
	#secondenter{
		bottom: 115px;
	}
	#preloader{
		bottom: 99px;
	}
}
/* STATISTIC PAGE CONDITIONS */
@media screen and (max-width: 1500px) {
	#mainblock {
		width: 1250px;
	}
	#incomes-lines-container, #expenses-lines-container {
		left: 315px; width: 210px;
	}
	#savingscircles {
		left: 330px;
	}
	#savingscircles {
		left: 355px;
		width: 345px;
		height: 345px;
	}
	#after-savings-value {
		top: 2%;
	}
	#before-savings-value {
		top: 0;
	}
}
@media screen and (max-width: 1200px) {
	#mainblock {
		width: 1060px;
	}
	#incomes-lines-container, #expenses-lines-container {
		left: 350px; width: 260px;
		padding-top: 72px;
	}
	#savingschart {
		width: 396px;
		height: 222px;
	}
	.months {
		width: 33px;
	}
	#savingscircles {
		left: 345px;
		width: 300px;
		height: 300px;
	}
	#after-savings-value {
		top:-5%;
	}
	#before-savings-value {
		top:-7%;
	}
	#firstcirclediv, #firstpendant {
		opacity: 0;
	}
	#small-circles-container {
		height: 260px;
	}
	#before-savings-value {
		font-size: 24px;
	}
}

/*================ @2x IMAGES FOR RETINA DISPLAYS ================   */

@media only screen and (-
Download .txt
gitextract_15q1n21c/

├── .github/
│   └── ISSUE_TEMPLATE/
│       └── bug-report-or-feature-request.md
├── .gitignore
├── .travis.yml
├── LICENCE
├── README.md
├── account-service/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── account/
│       │   │               ├── AccountApplication.java
│       │   │               ├── client/
│       │   │               │   ├── AuthServiceClient.java
│       │   │               │   ├── StatisticsServiceClient.java
│       │   │               │   └── StatisticsServiceClientFallback.java
│       │   │               ├── config/
│       │   │               │   └── ResourceServerConfig.java
│       │   │               ├── controller/
│       │   │               │   ├── AccountController.java
│       │   │               │   └── ErrorHandler.java
│       │   │               ├── domain/
│       │   │               │   ├── Account.java
│       │   │               │   ├── Currency.java
│       │   │               │   ├── Item.java
│       │   │               │   ├── Saving.java
│       │   │               │   ├── TimePeriod.java
│       │   │               │   └── User.java
│       │   │               ├── repository/
│       │   │               │   └── AccountRepository.java
│       │   │               └── service/
│       │   │                   ├── AccountService.java
│       │   │                   ├── AccountServiceImpl.java
│       │   │                   └── security/
│       │   │                       └── CustomUserInfoTokenServices.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── account/
│           │               ├── AccountServiceApplicationTests.java
│           │               ├── client/
│           │               │   └── StatisticsServiceClientFallbackTest.java
│           │               ├── controller/
│           │               │   └── AccountControllerTest.java
│           │               ├── repository/
│           │               │   └── AccountRepositoryTest.java
│           │               └── service/
│           │                   └── AccountServiceTest.java
│           └── resources/
│               ├── application.yml
│               └── bootstrap.yml
├── auth-service/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── auth/
│       │   │               ├── AuthApplication.java
│       │   │               ├── config/
│       │   │               │   ├── OAuth2AuthorizationConfig.java
│       │   │               │   └── WebSecurityConfig.java
│       │   │               ├── controller/
│       │   │               │   └── UserController.java
│       │   │               ├── domain/
│       │   │               │   └── User.java
│       │   │               ├── repository/
│       │   │               │   └── UserRepository.java
│       │   │               └── service/
│       │   │                   ├── UserService.java
│       │   │                   ├── UserServiceImpl.java
│       │   │                   └── security/
│       │   │                       └── MongoUserDetailsService.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── auth/
│           │               ├── AuthServiceApplicationTests.java
│           │               ├── controller/
│           │               │   └── UserControllerTest.java
│           │               ├── repository/
│           │               │   └── UserRepositoryTest.java
│           │               └── service/
│           │                   ├── UserServiceTest.java
│           │                   └── security/
│           │                       └── MongoUserDetailsServiceTest.java
│           └── resources/
│               ├── application.yml
│               └── bootstrap.yml
├── config/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── config/
│           │               ├── ConfigApplication.java
│           │               └── SecurityConfig.java
│           └── resources/
│               ├── application.yml
│               └── shared/
│                   ├── account-service.yml
│                   ├── application.yml
│                   ├── auth-service.yml
│                   ├── gateway.yml
│                   ├── monitoring.yml
│                   ├── notification-service.yml
│                   ├── registry.yml
│                   ├── statistics-service.yml
│                   └── turbine-stream-service.yml
├── docker-compose.dev.yml
├── docker-compose.yml
├── gateway/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── gateway/
│       │   │               └── GatewayApplication.java
│       │   └── resources/
│       │       ├── bootstrap.yml
│       │       └── static/
│       │           ├── attribution.html
│       │           ├── css/
│       │           │   ├── animation.css
│       │           │   ├── launch.css
│       │           │   └── style.css
│       │           ├── index.html
│       │           └── js/
│       │               ├── dashboard.js
│       │               ├── launch.js
│       │               ├── lib/
│       │               │   ├── extrascripts.js
│       │               │   └── touchscreens.js
│       │               ├── login.js
│       │               └── main.js
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── gateway/
│           │               └── GatewayApplicationTests.java
│           └── resources/
│               └── bootstrap.yml
├── mongodb/
│   ├── Dockerfile
│   ├── dump/
│   │   └── account-service-dump.js
│   └── init.sh
├── monitoring/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── monitoring/
│       │   │               └── MonitoringApplication.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── monitoring/
│           │               └── MonitoringApplicationTests.java
│           └── resources/
│               └── bootstrap.yml
├── notification-service/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── notification/
│       │   │               ├── NotificationServiceApplication.java
│       │   │               ├── client/
│       │   │               │   └── AccountServiceClient.java
│       │   │               ├── config/
│       │   │               │   └── ResourceServerConfig.java
│       │   │               ├── controller/
│       │   │               │   └── RecipientController.java
│       │   │               ├── domain/
│       │   │               │   ├── Frequency.java
│       │   │               │   ├── NotificationSettings.java
│       │   │               │   ├── NotificationType.java
│       │   │               │   └── Recipient.java
│       │   │               ├── repository/
│       │   │               │   ├── RecipientRepository.java
│       │   │               │   └── converter/
│       │   │               │       ├── FrequencyReaderConverter.java
│       │   │               │       └── FrequencyWriterConverter.java
│       │   │               └── service/
│       │   │                   ├── EmailService.java
│       │   │                   ├── EmailServiceImpl.java
│       │   │                   ├── NotificationService.java
│       │   │                   ├── NotificationServiceImpl.java
│       │   │                   ├── RecipientService.java
│       │   │                   └── RecipientServiceImpl.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── notification/
│           │               ├── NotificationServiceApplicationTests.java
│           │               ├── controller/
│           │               │   └── RecipientControllerTest.java
│           │               ├── repository/
│           │               │   └── RecipientRepositoryTest.java
│           │               └── service/
│           │                   ├── EmailServiceImplTest.java
│           │                   ├── NotificationServiceImplTest.java
│           │                   └── RecipientServiceImplTest.java
│           └── resources/
│               ├── application.yml
│               └── bootstrap.yml
├── pom.xml
├── registry/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── registry/
│           │               └── RegistryApplication.java
│           └── resources/
│               └── bootstrap.yml
├── statistics-service/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── piggymetrics/
│       │   │           └── statistics/
│       │   │               ├── StatisticsApplication.java
│       │   │               ├── client/
│       │   │               │   ├── ExchangeRatesClient.java
│       │   │               │   └── ExchangeRatesClientFallback.java
│       │   │               ├── config/
│       │   │               │   └── ResourceServerConfig.java
│       │   │               ├── controller/
│       │   │               │   └── StatisticsController.java
│       │   │               ├── domain/
│       │   │               │   ├── Account.java
│       │   │               │   ├── Currency.java
│       │   │               │   ├── ExchangeRatesContainer.java
│       │   │               │   ├── Item.java
│       │   │               │   ├── Saving.java
│       │   │               │   ├── TimePeriod.java
│       │   │               │   └── timeseries/
│       │   │               │       ├── DataPoint.java
│       │   │               │       ├── DataPointId.java
│       │   │               │       ├── ItemMetric.java
│       │   │               │       └── StatisticMetric.java
│       │   │               ├── repository/
│       │   │               │   ├── DataPointRepository.java
│       │   │               │   └── converter/
│       │   │               │       ├── DataPointIdReaderConverter.java
│       │   │               │       └── DataPointIdWriterConverter.java
│       │   │               └── service/
│       │   │                   ├── ExchangeRatesService.java
│       │   │                   ├── ExchangeRatesServiceImpl.java
│       │   │                   ├── StatisticsService.java
│       │   │                   ├── StatisticsServiceImpl.java
│       │   │                   └── security/
│       │   │                       └── CustomUserInfoTokenServices.java
│       │   └── resources/
│       │       └── bootstrap.yml
│       └── test/
│           ├── java/
│           │   └── com/
│           │       └── piggymetrics/
│           │           └── statistics/
│           │               ├── StatisticsServiceApplicationTests.java
│           │               ├── client/
│           │               │   └── ExchangeRatesClientTest.java
│           │               ├── controller/
│           │               │   └── StatisticsControllerTest.java
│           │               ├── repository/
│           │               │   └── DataPointRepositoryTest.java
│           │               └── service/
│           │                   ├── ExchangeRatesServiceImplTest.java
│           │                   └── StatisticsServiceImplTest.java
│           └── resources/
│               ├── application.yml
│               └── bootstrap.yml
└── turbine-stream-service/
    ├── Dockerfile
    ├── pom.xml
    └── src/
        ├── main/
        │   ├── java/
        │   │   └── com/
        │   │       └── piggymetrics/
        │   │           └── turbine/
        │   │               └── TurbineStreamServiceApplication.java
        │   └── resources/
        │       └── bootstrap.yml
        └── test/
            ├── java/
            │   └── com/
            │       └── piggymetrics/
            │           └── turbine/
            │               └── TurbineStreamServiceApplicationTests.java
            └── resources/
                └── bootstrap.yml
Download .txt
SYMBOL INDEX (521 symbols across 103 files)

FILE: account-service/src/main/java/com/piggymetrics/account/AccountApplication.java
  class AccountApplication (line 11) | @SpringBootApplication
    method main (line 19) | public static void main(String[] args) {

FILE: account-service/src/main/java/com/piggymetrics/account/client/AuthServiceClient.java
  type AuthServiceClient (line 9) | @FeignClient(name = "auth-service")
    method createUser (line 12) | @RequestMapping(method = RequestMethod.POST, value = "/uaa/users", con...

FILE: account-service/src/main/java/com/piggymetrics/account/client/StatisticsServiceClient.java
  type StatisticsServiceClient (line 10) | @FeignClient(name = "statistics-service", fallback = StatisticsServiceCl...
    method updateStatistics (line 13) | @RequestMapping(method = RequestMethod.PUT, value = "/statistics/{acco...

FILE: account-service/src/main/java/com/piggymetrics/account/client/StatisticsServiceClientFallback.java
  class StatisticsServiceClientFallback (line 11) | @Component
    method updateStatistics (line 14) | @Override

FILE: account-service/src/main/java/com/piggymetrics/account/config/ResourceServerConfig.java
  class ResourceServerConfig (line 22) | @Configuration
    method ResourceServerConfig (line 28) | @Autowired
    method clientCredentialsResourceDetails (line 33) | @Bean
    method oauth2FeignRequestInterceptor (line 39) | @Bean
    method clientCredentialsRestTemplate (line 44) | @Bean
    method tokenServices (line 49) | @Bean
    method configure (line 54) | @Override

FILE: account-service/src/main/java/com/piggymetrics/account/controller/AccountController.java
  class AccountController (line 13) | @RestController
    method getAccountByName (line 19) | @PreAuthorize("#oauth2.hasScope('server') or #name.equals('demo')")
    method getCurrentAccount (line 25) | @RequestMapping(path = "/current", method = RequestMethod.GET)
    method saveCurrentAccount (line 30) | @RequestMapping(path = "/current", method = RequestMethod.PUT)
    method createNewAccount (line 35) | @RequestMapping(path = "/", method = RequestMethod.POST)

FILE: account-service/src/main/java/com/piggymetrics/account/controller/ErrorHandler.java
  class ErrorHandler (line 10) | @ControllerAdvice
    method processValidationError (line 17) | @ExceptionHandler(IllegalArgumentException.class)

FILE: account-service/src/main/java/com/piggymetrics/account/domain/Account.java
  class Account (line 13) | @Document(collection = "accounts")
    method getName (line 35) | public String getName() {
    method setName (line 39) | public void setName(String name) {
    method getLastSeen (line 43) | public Date getLastSeen() {
    method setLastSeen (line 47) | public void setLastSeen(Date lastSeen) {
    method getIncomes (line 51) | public List<Item> getIncomes() {
    method setIncomes (line 55) | public void setIncomes(List<Item> incomes) {
    method getExpenses (line 59) | public List<Item> getExpenses() {
    method setExpenses (line 63) | public void setExpenses(List<Item> expenses) {
    method getSaving (line 67) | public Saving getSaving() {
    method setSaving (line 71) | public void setSaving(Saving saving) {
    method getNote (line 75) | public String getNote() {
    method setNote (line 79) | public void setNote(String note) {

FILE: account-service/src/main/java/com/piggymetrics/account/domain/Currency.java
  type Currency (line 3) | public enum Currency {
    method getDefault (line 7) | public static Currency getDefault() {

FILE: account-service/src/main/java/com/piggymetrics/account/domain/Item.java
  class Item (line 8) | public class Item {
    method getTitle (line 26) | public String getTitle() {
    method setTitle (line 30) | public void setTitle(String title) {
    method getAmount (line 34) | public BigDecimal getAmount() {
    method setAmount (line 38) | public void setAmount(BigDecimal amount) {
    method getCurrency (line 42) | public Currency getCurrency() {
    method setCurrency (line 46) | public void setCurrency(Currency currency) {
    method getPeriod (line 50) | public TimePeriod getPeriod() {
    method setPeriod (line 54) | public void setPeriod(TimePeriod period) {
    method getIcon (line 58) | public String getIcon() {
    method setIcon (line 62) | public void setIcon(String icon) {

FILE: account-service/src/main/java/com/piggymetrics/account/domain/Saving.java
  class Saving (line 6) | public class Saving {
    method getAmount (line 23) | public BigDecimal getAmount() {
    method setAmount (line 27) | public void setAmount(BigDecimal amount) {
    method getCurrency (line 31) | public Currency getCurrency() {
    method setCurrency (line 35) | public void setCurrency(Currency currency) {
    method getInterest (line 39) | public BigDecimal getInterest() {
    method setInterest (line 43) | public void setInterest(BigDecimal interest) {
    method getDeposit (line 47) | public Boolean getDeposit() {
    method setDeposit (line 51) | public void setDeposit(Boolean deposit) {
    method getCapitalization (line 55) | public Boolean getCapitalization() {
    method setCapitalization (line 59) | public void setCapitalization(Boolean capitalization) {

FILE: account-service/src/main/java/com/piggymetrics/account/domain/TimePeriod.java
  type TimePeriod (line 3) | public enum TimePeriod {

FILE: account-service/src/main/java/com/piggymetrics/account/domain/User.java
  class User (line 7) | public class User {
    method getUsername (line 17) | public String getUsername() {
    method setUsername (line 21) | public void setUsername(String username) {
    method getPassword (line 25) | public String getPassword() {
    method setPassword (line 29) | public void setPassword(String password) {

FILE: account-service/src/main/java/com/piggymetrics/account/repository/AccountRepository.java
  type AccountRepository (line 7) | @Repository
    method findByName (line 10) | Account findByName(String name);

FILE: account-service/src/main/java/com/piggymetrics/account/service/AccountService.java
  type AccountService (line 6) | public interface AccountService {
    method findByName (line 14) | Account findByName(String accountName);
    method create (line 24) | Account create(User user);
    method saveChanges (line 33) | void saveChanges(String name, Account update);

FILE: account-service/src/main/java/com/piggymetrics/account/service/AccountServiceImpl.java
  class AccountServiceImpl (line 19) | @Service
    method findByName (line 36) | @Override
    method create (line 45) | @Override
    method saveChanges (line 75) | @Override

FILE: account-service/src/main/java/com/piggymetrics/account/service/security/CustomUserInfoTokenServices.java
  class CustomUserInfoTokenServices (line 29) | public class CustomUserInfoTokenServices implements ResourceServerTokenS...
    method CustomUserInfoTokenServices (line 46) | public CustomUserInfoTokenServices(String userInfoEndpointUrl, String ...
    method setTokenType (line 51) | public void setTokenType(String tokenType) {
    method setRestTemplate (line 55) | public void setRestTemplate(OAuth2RestOperations restTemplate) {
    method setAuthoritiesExtractor (line 59) | public void setAuthoritiesExtractor(AuthoritiesExtractor authoritiesEx...
    method loadAuthentication (line 63) | @Override
    method extractAuthentication (line 74) | private OAuth2Authentication extractAuthentication(Map<String, Object>...
    method getPrincipal (line 85) | private Object getPrincipal(Map<String, Object> map) {
    method getRequest (line 94) | @SuppressWarnings({ "unchecked" })
    method readAccessToken (line 106) | @Override
    method getMap (line 111) | @SuppressWarnings({ "unchecked" })

FILE: account-service/src/test/java/com/piggymetrics/account/AccountServiceApplicationTests.java
  class AccountServiceApplicationTests (line 8) | @RunWith(SpringRunner.class)
    method contextLoads (line 12) | @Test

FILE: account-service/src/test/java/com/piggymetrics/account/client/StatisticsServiceClientFallbackTest.java
  class StatisticsServiceClientFallbackTest (line 18) | @RunWith(SpringRunner.class)
    method setup (line 29) | @Before
    method testUpdateStatisticsWithFailFallback (line 34) | @Test

FILE: account-service/src/test/java/com/piggymetrics/account/controller/AccountControllerTest.java
  class AccountControllerTest (line 28) | @RunWith(SpringRunner.class)
    method setup (line 42) | @Before
    method shouldGetAccountByName (line 48) | @Test
    method shouldGetCurrentAccount (line 61) | @Test
    method shouldSaveCurrentAccount (line 74) | @Test
    method shouldFailOnValidationTryingToSaveCurrentAccount (line 112) | @Test
    method shouldRegisterNewAccount (line 124) | @Test
    method shouldFailOnValidationTryingToRegisterNewAccount (line 137) | @Test

FILE: account-service/src/test/java/com/piggymetrics/account/repository/AccountRepositoryTest.java
  class AccountRepositoryTest (line 20) | @RunWith(SpringRunner.class)
    method shouldFindAccountByName (line 27) | @Test
    method getStubAccount (line 40) | private Account getStubAccount() {

FILE: account-service/src/test/java/com/piggymetrics/account/service/AccountServiceTest.java
  class AccountServiceTest (line 20) | public class AccountServiceTest {
    method setup (line 34) | @Before
    method shouldFindByName (line 39) | @Test
    method shouldFailWhenNameIsEmpty (line 51) | @Test(expected = IllegalArgumentException.class)
    method shouldCreateAccountWithGivenUser (line 56) | @Test
    method shouldSaveChangesWhenUpdatedAccountGiven (line 76) | @Test
    method shouldFailWhenNoAccountsExistedWithGivenName (line 140) | @Test(expected = IllegalArgumentException.class)

FILE: auth-service/src/main/java/com/piggymetrics/auth/AuthApplication.java
  class AuthApplication (line 9) | @SpringBootApplication
    method main (line 15) | public static void main(String[] args) {

FILE: auth-service/src/main/java/com/piggymetrics/auth/config/OAuth2AuthorizationConfig.java
  class OAuth2AuthorizationConfig (line 21) | @Configuration
    method configure (line 38) | @Override
    method configure (line 66) | @Override
    method configure (line 74) | @Override

FILE: auth-service/src/main/java/com/piggymetrics/auth/config/WebSecurityConfig.java
  class WebSecurityConfig (line 16) | @Configuration
    method configure (line 22) | @Override
    method configure (line 32) | @Override
    method authenticationManagerBean (line 38) | @Override

FILE: auth-service/src/main/java/com/piggymetrics/auth/controller/UserController.java
  class UserController (line 15) | @RestController
    method getUser (line 22) | @RequestMapping(value = "/current", method = RequestMethod.GET)
    method createUser (line 27) | @PreAuthorize("#oauth2.hasScope('server')")

FILE: auth-service/src/main/java/com/piggymetrics/auth/domain/User.java
  class User (line 10) | @Document(collection = "users")
    method getPassword (line 18) | @Override
    method getUsername (line 23) | @Override
    method getAuthorities (line 28) | @Override
    method setUsername (line 33) | public void setUsername(String username) {
    method setPassword (line 37) | public void setPassword(String password) {
    method isAccountNonExpired (line 41) | @Override
    method isAccountNonLocked (line 46) | @Override
    method isCredentialsNonExpired (line 51) | @Override
    method isEnabled (line 56) | @Override

FILE: auth-service/src/main/java/com/piggymetrics/auth/repository/UserRepository.java
  type UserRepository (line 7) | @Repository

FILE: auth-service/src/main/java/com/piggymetrics/auth/service/UserService.java
  type UserService (line 5) | public interface UserService {
    method create (line 7) | void create(User user);

FILE: auth-service/src/main/java/com/piggymetrics/auth/service/UserServiceImpl.java
  class UserServiceImpl (line 14) | @Service
    method create (line 24) | @Override

FILE: auth-service/src/main/java/com/piggymetrics/auth/service/security/MongoUserDetailsService.java
  class MongoUserDetailsService (line 10) | @Service
    method loadUserByUsername (line 16) | @Override

FILE: auth-service/src/test/java/com/piggymetrics/auth/AuthServiceApplicationTests.java
  class AuthServiceApplicationTests (line 8) | @RunWith(SpringRunner.class)
    method contextLoads (line 12) | @Test

FILE: auth-service/src/test/java/com/piggymetrics/auth/controller/UserControllerTest.java
  class UserControllerTest (line 24) | @RunWith(SpringRunner.class)
    method setup (line 38) | @Before
    method shouldCreateNewUser (line 44) | @Test
    method shouldFailWhenUserIsNotValid (line 57) | @Test
    method shouldReturnCurrentUser (line 68) | @Test

FILE: auth-service/src/test/java/com/piggymetrics/auth/repository/UserRepositoryTest.java
  class UserRepositoryTest (line 18) | @RunWith(SpringRunner.class)
    method shouldSaveAndFindUserByName (line 25) | @Test

FILE: auth-service/src/test/java/com/piggymetrics/auth/service/UserServiceTest.java
  class UserServiceTest (line 15) | public class UserServiceTest {
    method setup (line 23) | @Before
    method shouldCreateUser (line 28) | @Test
    method shouldFailWhenUserAlreadyExists (line 39) | @Test(expected = IllegalArgumentException.class)

FILE: auth-service/src/test/java/com/piggymetrics/auth/service/security/MongoUserDetailsServiceTest.java
  class MongoUserDetailsServiceTest (line 19) | public class MongoUserDetailsServiceTest {
    method setup (line 27) | @Before
    method shouldLoadByUsernameWhenUserExists (line 32) | @Test
    method shouldFailToLoadByUsernameWhenUserNotExists (line 43) | @Test(expected = UsernameNotFoundException.class)

FILE: config/src/main/java/com/piggymetrics/config/ConfigApplication.java
  class ConfigApplication (line 7) | @SpringBootApplication
    method main (line 11) | public static void main(String[] args) {

FILE: config/src/main/java/com/piggymetrics/config/SecurityConfig.java
  class SecurityConfig (line 10) | @Configuration
    method configure (line 13) | @Override

FILE: gateway/src/main/java/com/piggymetrics/gateway/GatewayApplication.java
  class GatewayApplication (line 8) | @SpringBootApplication
    method main (line 13) | public static void main(String[] args) {

FILE: gateway/src/main/resources/static/js/dashboard.js
  function getConverted (line 70) | function getConverted(column) {
  function initStatisticPage (line 119) | function initStatisticPage() {
  function separateNumber (line 454) | function separateNumber(val) {
  function animatecircle (line 465) | function animatecircle(beforevalue, aftervalue, sum, title) {
  function simpleanimatecircle (line 541) | function simpleanimatecircle(before, after, duration) {
  function initSavingsSlider (line 635) | function initSavingsSlider() {
  function drawChartLine (line 732) | function drawChartLine(position) {

FILE: gateway/src/main/resources/static/js/launch.js
  function requestOauthToken (line 12) | function requestOauthToken(username, password) {
  function getOauthTokenFromStorage (line 40) | function getOauthTokenFromStorage() {
  function removeOauthTokenFromStorage (line 44) | function removeOauthTokenFromStorage() {
  function getCurrentAccount (line 52) | function getCurrentAccount() {
  function showGreetingPage (line 97) | function showGreetingPage(account) {
  function showLoginForm (line 105) | function showLoginForm() {

FILE: gateway/src/main/resources/static/js/lib/extrascripts.js
  function m (line 31) | function m(b,a,c){void 0===b.selectionStart?(b.focus(),b=b.createTextRan...
  function B (line 31) | function B(b,a){f.each(a,function(c,d){"function"===typeof d?a[c]=d(b,a,...
  function p (line 31) | function p(b,a){"string"===typeof b[a]&&(b[a]*=1)}
  function w (line 31) | function w(b,a){B(b,a);a.oEvent=null;a.tagList="B CAPTION CITE CODE DD D...
  function h (line 33) | function h(b,a,c){if(a.aSign)for(;-1<b.indexOf(a.aSign);)b=b.replace(a.a...
  function x (line 35) | function x(b,a,c){if(a&&c){var d=b.split(a);d[1]&&d[1].length>c&&(0<c?(d...
  function r (line 35) | function r(b,a,c){a&&"."!==a&&(b=b.replace(a,"."));c&&"-"!==c&&(b=b.repl...
  function y (line 35) | function y(b,a){var c=b.indexOf("."),d=+b;-1!==c&&(1E-6>d&&-1<d?(b=+b,1E...
  function z (line 36) | function z(b,a,c){c&&"-"!==c&&(b=b.replace("-",c));a&&"."!==a&&(b=b.repl...
  function s (line 36) | function s(b,a){b=h(b,a);b=x(b,a.aDec,a.mDec);b=r(b,a.aDec,a.aNeg);var c...
  function q (line 36) | function q(b,a,c){return""===b||b===a.aNeg?"zero"===a.wEmpty?b+
  function t (line 37) | function t(b,a){b=h(b,a);var c=b.replace(",","."),d=q(b,a,!0);if(null!==...
  function u (line 38) | function u(b,a){b=""===b?"0":b.toString();p(a,"mDec");var c="",d=0,e="",...
  function A (line 40) | function A(b,a){this.settings=a;this.that=b;this.$that=f(b);this.formatt...
  function l (line 41) | function l(b){"string"===typeof b&&(b=b.replace(/\[/g,"\\[").replace(/\]...
  function k (line 41) | function k(b,a,c){var d=b.data("autoNumeric");d||(d={},b.data("autoNumer...
  function doSelect (line 73) | function doSelect(){var option=select.find('option');var optionSelected=...
  function t (line 76) | function t(e){throw new RangeError("noUiSlider: "+e)}
  function n (line 76) | function n(e,n,r){(e[n]||e[r])&&e[n]===e[r]&&t("(Link) '"+n+"' can't mat...
  function r (line 76) | function r(e){return"number"===typeof e&&!isNaN(e)&&isFinite(e)}
  function i (line 76) | function i(t){return e.isArray(t)?t:[t]}
  function s (line 76) | function s(e,t){e.addClass(t);setTimeout(function(){e.removeClass(t)},300)}
  function o (line 76) | function o(e,t){return 100*t/(e[1]-e[0])}
  function u (line 76) | function u(e,t){if(t>=e.d.slice(-1)[0])return 100;for(var n=1,r,i,s;t>=e...
  function a (line 76) | function a(e,t){for(var n=1,r;t>=e.c[n];)n++;if(e.m)return r=e.c[n-1],n=...
  function f (line 76) | function f(r){void 0===r&&(r={});"object"!==typeof r&&t("(Format) 'forma...
  function l (line 76) | function l(t,n){if(!(this instanceof l))throw Error("Link: Don't use Lin...
  function c (line 76) | function c(e,n){r(n)||t("'step' is not numeric.");e.h[0]=n}
  function h (line 76) | function h(n,i){("object"!==typeof i||e.isArray(i))&&t("'range' is not a...
  function p (line 76) | function p(n,r){"number"===typeof r&&(r=[r]);(!e.isArray(r)||!r.length||...
  function d (line 76) | function d(e,n){e.m=n;"boolean"!==typeof n&&t("'snap' option must be a b...
  function v (line 76) | function v(e,n){"lower"===n&&1===e.a?e.i=1:"upper"===n&&1===e.a?e.i=2:!0...
  function m (line 76) | function m(e,n){switch(n){case"horizontal":e.k=0;break;case"vertical":e....
  function g (line 76) | function g(e,n){2<e.c.length&&t("'margin' option is only supported on li...
  function y (line 76) | function y(e,n){switch(n){case"ltr":e.dir=0;break;case"rtl":e.dir=1;e.i=...
  function b (line 76) | function b(e,n){"string"!==typeof n&&t("'behaviour' must be a string con...
  function w (line 76) | function w(n,r,i){n.o=[r.lower,r.upper];n.g=new f(r.format);e.each(n.o,f...
  function E (line 76) | function E(n,r){var i={c:[],d:[],h:[!1],margin:0},s;s={step:{e:!1,f:c},r...
  function S (line 76) | function S(t,n){var r=e("<div><div/></div>").addClass(P[2]),i=["-lower",...
  function x (line 76) | function x(t,n){n.j&&(n=new l({target:e(n.j).clone().appendTo(t),method:...
  function T (line 76) | function T(e,t){var n,r=[];for(n=0;n<e.a;n++){var i=r,s=n,o=e.o[n],u=t[n...
  function N (line 76) | function N(e,t,n){switch(e){case 1:t.addClass(P[7]);n[0].addClass(P[6]);...
  function C (line 76) | function C(e,t){var n,r=[];for(n=0;n<e.a;n++)r.push(S(e,n).appendTo(t));...
  function k (line 76) | function k(t,n){n.addClass([P[0],P[8+t.dir],P[4+t.k]].join(" "));return ...
  function L (line 76) | function L(t,n,r){function i(){return b[["width","height"][n.k]]()}funct...
  function A (line 76) | function A(e){this.length||t("Can't initialize slider on empty selection...
  function O (line 76) | function O(t){return this.each(function(){var n=e(this).val(),r=this.r()...
  function t (line 76) | function t(e){return e.split("").reverse().join("")}
  function t (line 76) | function t(e){return e.replace(/[\-\/\\\^$*+?.()|\[\]{}]/g,"\\$&")}
  function b (line 97) | function b(b){var c=b.data;b.isDefaultPrevented()||(b.preventDefault(),a...
  function c (line 97) | function c(b){var c=b.target,d=a(c);if(!d.is("[type=submit],[type=image]...
  function d (line 97) | function d(){if(a.fn.ajaxSubmit.debug){var b="[jquery.form] "+Array.prot...
  function c (line 97) | function c(c){var d,e,f=a.param(c,b.traditional).split("&"),g=f.length,h...
  function g (line 97) | function g(d){for(var e=new FormData,f=0;f<d.length;f++)e.append(d[f].na...
  function h (line 97) | function h(c){function e(a){var b=null;try{a.contentWindow&&(b=a.content...

FILE: gateway/src/main/resources/static/js/lib/touchscreens.js
  function FastClick (line 10) | function FastClick(a){function b(a,b){return function(){return a.apply(b...
  function u (line 41) | function u(B){if(B&&(B.allowPageScroll===undefined&&(B.swipe!==undefined...
  function z (line 41) | function z(a0,aq){var av=(a||!aq.fallbackToMouseEvents),G=av?"touchstart...

FILE: gateway/src/main/resources/static/js/login.js
  function login (line 1) | function login() {

	$("#piggy").toggleClass("loadingspin");
	$("#second...
  function logout (line 1) | function logout() {
    removeOauthTokenFromStorage();
    location.relo...
  function initialShaking (line 1) | function initialShaking(){
	autoShake();
	setTimeout(autoShake, 1900);
}
  function autoShake (line 1) | function autoShake() {
	$("#piggy").toggleClass("auto-shake");
}
  function OnHoverShaking (line 1) | function OnHoverShaking() {
	hoverShake();
	setTimeout(hoverShake, 1700);
}
  function hoverShake (line 1) | function hoverShake() {
	$("#piggy").toggleClass("hover-shake");
}
  function toggleInfo (line 1) | function toggleInfo() {
	$("#infopage").toggle();
}
  function flipForm (line 1) | function flipForm() {
	$("#cube").toggleClass("flippedform");
	$("#front...

FILE: gateway/src/main/resources/static/js/main.js
  function initAccount (line 6) | function initAccount(account) {
  function User (line 23) | function User(username, lastSeen, currency, note) {
  function Savings (line 35) | function Savings(money, deposit, capitalization, interest) {
  function AddIncome (line 42) | function AddIncome(income_id, title, icon, currency, period, amount){
  function AddExpense (line 53) | function AddExpense(expense_id, title, icon, currency, period, amount){
  function escape (line 78) | function escape(string) {
  function sanitize (line 84) | function sanitize(obj) {
  function initGreetingPage (line 95) | function initGreetingPage() {
  function initSettingsPage (line 130) | function initSettingsPage() {
  function greetingPageAgain (line 150) | function greetingPageAgain() {
  function showGreetingUnits (line 174) | function showGreetingUnits() {
  function hideGreetingUnits (line 179) | function hideGreetingUnits() {
  function addNotes (line 186) | function addNotes() {
  function addSavings (line 191) | function addSavings() {
  function addItems (line 208) | function addItems() {
  function itemsPosition (line 229) | function itemsPosition(transaction) {
  function checkSlidersLength (line 240) | function checkSlidersLength() {
  function checkPeriod (line 261) | function checkPeriod(period) {
  function checkCurrency (line 283) | function checkCurrency(currency) {
  function debounce (line 299) | function debounce(f, ms) {
  function Up (line 324) | function Up(transaction) {
  function Down (line 351) | function Down(transaction) {
  function startOfExpenseList (line 379) | function startOfExpenseList(transaction) {
  function endOfExpenseList (line 382) | function endOfExpenseList(transaction) {
  function startOfIncomeList (line 385) | function startOfIncomeList(transaction) {
  function endOfIncomeList (line 388) | function endOfIncomeList(transaction) {
  function addNewItem (line 395) | function addNewItem() {
  function addNewDiv (line 420) | function addNewDiv(whichColumn, itemId, itemTitle, itemIcon, itemCurrenc...
  function itemClick (line 427) | function itemClick(item) {
  function editOldDiv (line 491) | function editOldDiv(whichColumn, itemId, itemTitle, itemIcon, itemCurren...
  function runConvert (line 498) | function runConvert() {
  function addOrSaveItems (line 533) | function addOrSaveItems () {
  function checkModalFields (line 558) | function checkModalFields (itemValue, itemTitle) {
  function turnOffModal (line 587) | function turnOffModal() {
  function modalFontSize (line 595) | function modalFontSize() {
  function moveRuble (line 702) | function moveRuble() {
  function launchStatistic (line 833) | function launchStatistic() {
  function jsonDataSave (line 868) | function jsonDataSave() {
  function fadeStatistic (line 901) | function fadeStatistic() {

FILE: gateway/src/test/java/com/piggymetrics/gateway/GatewayApplicationTests.java
  class GatewayApplicationTests (line 8) | @RunWith(SpringRunner.class)
    method contextLoads (line 12) | @Test
    method fire (line 16) | @Test

FILE: monitoring/src/main/java/com/piggymetrics/monitoring/MonitoringApplication.java
  class MonitoringApplication (line 7) | @SpringBootApplication
    method main (line 11) | public static void main(String[] args) {

FILE: monitoring/src/test/java/com/piggymetrics/monitoring/MonitoringApplicationTests.java
  class MonitoringApplicationTests (line 8) | @RunWith(SpringRunner.class)
    method contextLoads (line 12) | @Test

FILE: notification-service/src/main/java/com/piggymetrics/notification/NotificationServiceApplication.java
  class NotificationServiceApplication (line 18) | @SpringBootApplication
    method main (line 26) | public static void main(String[] args) {
    class CustomConversionsConfig (line 30) | @Configuration
      method customConversions (line 33) | @Bean

FILE: notification-service/src/main/java/com/piggymetrics/notification/client/AccountServiceClient.java
  type AccountServiceClient (line 9) | @FeignClient(name = "account-service")
    method getAccount (line 12) | @RequestMapping(method = RequestMethod.GET, value = "/accounts/{accoun...

FILE: notification-service/src/main/java/com/piggymetrics/notification/config/ResourceServerConfig.java
  class ResourceServerConfig (line 17) | @Configuration
    method clientCredentialsResourceDetails (line 20) | @Bean
    method oauth2FeignRequestInterceptor (line 25) | @Bean
    method clientCredentialsRestTemplate (line 30) | @Bean

FILE: notification-service/src/main/java/com/piggymetrics/notification/controller/RecipientController.java
  class RecipientController (line 14) | @RestController
    method getCurrentNotificationsSettings (line 21) | @RequestMapping(path = "/current", method = RequestMethod.GET)
    method saveCurrentNotificationsSettings (line 26) | @RequestMapping(path = "/current", method = RequestMethod.PUT)

FILE: notification-service/src/main/java/com/piggymetrics/notification/domain/Frequency.java
  type Frequency (line 5) | public enum Frequency {
    method Frequency (line 11) | Frequency(int days) {
    method getDays (line 15) | public int getDays() {
    method withDays (line 19) | public static Frequency withDays(int days) {

FILE: notification-service/src/main/java/com/piggymetrics/notification/domain/NotificationSettings.java
  class NotificationSettings (line 6) | public class NotificationSettings {
    method getActive (line 16) | public Boolean getActive() {
    method setActive (line 20) | public void setActive(Boolean active) {
    method getFrequency (line 24) | public Frequency getFrequency() {
    method setFrequency (line 28) | public void setFrequency(Frequency frequency) {
    method getLastNotified (line 32) | public Date getLastNotified() {
    method setLastNotified (line 36) | public void setLastNotified(Date lastNotified) {

FILE: notification-service/src/main/java/com/piggymetrics/notification/domain/NotificationType.java
  type NotificationType (line 3) | public enum NotificationType {
    method NotificationType (line 12) | NotificationType(String subject, String text, String attachment) {
    method getSubject (line 18) | public String getSubject() {
    method getText (line 22) | public String getText() {
    method getAttachment (line 26) | public String getAttachment() {

FILE: notification-service/src/main/java/com/piggymetrics/notification/domain/Recipient.java
  class Recipient (line 11) | @Document(collection = "recipients")
    method getAccountName (line 24) | public String getAccountName() {
    method setAccountName (line 28) | public void setAccountName(String accountName) {
    method getEmail (line 32) | public String getEmail() {
    method setEmail (line 36) | public void setEmail(String email) {
    method getScheduledNotifications (line 40) | public Map<NotificationType, NotificationSettings> getScheduledNotific...
    method setScheduledNotifications (line 44) | public void setScheduledNotifications(Map<NotificationType, Notificati...
    method toString (line 48) | @Override

FILE: notification-service/src/main/java/com/piggymetrics/notification/repository/RecipientRepository.java
  type RecipientRepository (line 10) | @Repository
    method findByAccountName (line 13) | Recipient findByAccountName(String name);
    method findReadyForBackup (line 15) | @Query("{ $and: [ {'scheduledNotifications.BACKUP.active': true }, { $...
    method findReadyForRemind (line 19) | @Query("{ $and: [ {'scheduledNotifications.REMIND.active': true }, { $...

FILE: notification-service/src/main/java/com/piggymetrics/notification/repository/converter/FrequencyReaderConverter.java
  class FrequencyReaderConverter (line 7) | @Component
    method convert (line 10) | @Override

FILE: notification-service/src/main/java/com/piggymetrics/notification/repository/converter/FrequencyWriterConverter.java
  class FrequencyWriterConverter (line 7) | @Component
    method convert (line 10) | @Override

FILE: notification-service/src/main/java/com/piggymetrics/notification/service/EmailService.java
  type EmailService (line 9) | public interface EmailService {
    method send (line 11) | void send(NotificationType type, Recipient recipient, String attachmen...

FILE: notification-service/src/main/java/com/piggymetrics/notification/service/EmailServiceImpl.java
  class EmailServiceImpl (line 21) | @Service
    method send (line 33) | @Override

FILE: notification-service/src/main/java/com/piggymetrics/notification/service/NotificationService.java
  type NotificationService (line 3) | public interface NotificationService {
    method sendBackupNotifications (line 5) | void sendBackupNotifications();
    method sendRemindNotifications (line 7) | void sendRemindNotifications();

FILE: notification-service/src/main/java/com/piggymetrics/notification/service/NotificationServiceImpl.java
  class NotificationServiceImpl (line 15) | @Service
    method sendBackupNotifications (line 29) | @Override
    method sendRemindNotifications (line 49) | @Override

FILE: notification-service/src/main/java/com/piggymetrics/notification/service/RecipientService.java
  type RecipientService (line 8) | public interface RecipientService {
    method findByAccountName (line 16) | Recipient findByAccountName(String accountName);
    method findReadyToNotify (line 25) | List<Recipient> findReadyToNotify(NotificationType type);
    method save (line 34) | Recipient save(String accountName, Recipient recipient);
    method markNotified (line 43) | void markNotified(NotificationType type, Recipient recipient);

FILE: notification-service/src/main/java/com/piggymetrics/notification/service/RecipientServiceImpl.java
  class RecipientServiceImpl (line 15) | @Service
    method findByAccountName (line 23) | @Override
    method save (line 32) | @Override
    method findReadyToNotify (line 53) | @Override
    method markNotified (line 68) | @Override

FILE: notification-service/src/test/java/com/piggymetrics/notification/NotificationServiceApplicationTests.java
  class NotificationServiceApplicationTests (line 8) | @RunWith(SpringRunner.class)
    method contextLoads (line 12) | @Test

FILE: notification-service/src/test/java/com/piggymetrics/notification/controller/RecipientControllerTest.java
  class RecipientControllerTest (line 29) | @RunWith(SpringRunner.class)
    method setup (line 43) | @Before
    method shouldSaveCurrentRecipientSettings (line 49) | @Test
    method shouldGetCurrentRecipientSettings (line 59) | @Test
    method getStubRecipient (line 70) | private Recipient getStubRecipient() {

FILE: notification-service/src/test/java/com/piggymetrics/notification/repository/RecipientRepositoryTest.java
  class RecipientRepositoryTest (line 22) | @RunWith(SpringRunner.class)
    method shouldFindByAccountName (line 29) | @Test
    method shouldFindReadyForRemindWhenFrequencyIsWeeklyAndLastNotifiedWas8DaysAgo (line 71) | @Test
    method shouldNotFindReadyForRemindWhenFrequencyIsWeeklyAndLastNotifiedWasYesterday (line 92) | @Test
    method shouldNotFindReadyForRemindWhenNotificationIsNotActive (line 113) | @Test
    method shouldNotFindReadyForBackupWhenFrequencyIsQuaterly (line 134) | @Test

FILE: notification-service/src/test/java/com/piggymetrics/notification/service/EmailServiceImplTest.java
  class EmailServiceImplTest (line 25) | public class EmailServiceImplTest {
    method setup (line 39) | @Before
    method shouldSendBackupEmail (line 46) | @Test
    method shouldSendRemindEmail (line 70) | @Test

FILE: notification-service/src/test/java/com/piggymetrics/notification/service/NotificationServiceImplTest.java
  class NotificationServiceImplTest (line 18) | public class NotificationServiceImplTest {
    method setup (line 32) | @Before
    method shouldSendBackupNotificationsEvenWhenErrorsOccursForSomeRecipients (line 37) | @Test
    method shouldSendRemindNotificationsEvenWhenErrorsOccursForSomeRecipients (line 63) | @Test

FILE: notification-service/src/test/java/com/piggymetrics/notification/service/RecipientServiceImplTest.java
  class RecipientServiceImplTest (line 24) | public class RecipientServiceImplTest {
    method setup (line 32) | @Before
    method shouldFindByAccountName (line 37) | @Test
    method shouldFailToFindRecipientWhenAccountNameIsEmpty (line 48) | @Test(expected = IllegalArgumentException.class)
    method shouldSaveRecipient (line 53) | @Test
    method shouldFindReadyToNotifyWhenNotificationTypeIsBackup (line 80) | @Test
    method shouldFindReadyToNotifyWhenNotificationTypeIsRemind (line 89) | @Test
    method shouldMarkAsNotified (line 98) | @Test

FILE: registry/src/main/java/com/piggymetrics/registry/RegistryApplication.java
  class RegistryApplication (line 7) | @SpringBootApplication
    method main (line 11) | public static void main(String[] args) {

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/StatisticsApplication.java
  class StatisticsApplication (line 21) | @SpringBootApplication
    method main (line 28) | public static void main(String[] args) {
    class CustomConversionsConfig (line 32) | @Configuration
      method customConversions (line 35) | @Bean

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/client/ExchangeRatesClient.java
  type ExchangeRatesClient (line 10) | @FeignClient(url = "${rates.url}", name = "rates-client", fallback = Exc...
    method getRates (line 13) | @RequestMapping(method = RequestMethod.GET, value = "/latest")

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/client/ExchangeRatesClientFallback.java
  class ExchangeRatesClientFallback (line 9) | @Component
    method getRates (line 12) | @Override

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/config/ResourceServerConfig.java
  class ResourceServerConfig (line 15) | @EnableResourceServer
    method tokenServices (line 21) | @Bean

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/controller/StatisticsController.java
  class StatisticsController (line 14) | @RestController
    method getCurrentAccountStatistics (line 20) | @RequestMapping(value = "/current", method = RequestMethod.GET)
    method getStatisticsByAccountName (line 25) | @PreAuthorize("#oauth2.hasScope('server') or #accountName.equals('demo...
    method saveAccountStatistics (line 31) | @PreAuthorize("#oauth2.hasScope('server')")

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/Account.java
  class Account (line 10) | @Document(collection = "accounts")
    method getIncomes (line 26) | public List<Item> getIncomes() {
    method setIncomes (line 30) | public void setIncomes(List<Item> incomes) {
    method getExpenses (line 34) | public List<Item> getExpenses() {
    method setExpenses (line 38) | public void setExpenses(List<Item> expenses) {
    method getSaving (line 42) | public Saving getSaving() {
    method setSaving (line 46) | public void setSaving(Saving saving) {

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/Currency.java
  type Currency (line 3) | public enum Currency {
    method getBase (line 7) | public static Currency getBase() {

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/ExchangeRatesContainer.java
  class ExchangeRatesContainer (line 9) | @JsonIgnoreProperties(ignoreUnknown = true, value = {"date"})
    method getDate (line 18) | public LocalDate getDate() {
    method setDate (line 22) | public void setDate(LocalDate date) {
    method getBase (line 26) | public Currency getBase() {
    method setBase (line 30) | public void setBase(Currency base) {
    method getRates (line 34) | public Map<String, BigDecimal> getRates() {
    method setRates (line 38) | public void setRates(Map<String, BigDecimal> rates) {
    method toString (line 42) | @Override

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/Item.java
  class Item (line 8) | public class Item {
    method getTitle (line 23) | public String getTitle() {
    method setTitle (line 27) | public void setTitle(String title) {
    method getAmount (line 31) | public BigDecimal getAmount() {
    method setAmount (line 35) | public void setAmount(BigDecimal amount) {
    method getCurrency (line 39) | public Currency getCurrency() {
    method setCurrency (line 43) | public void setCurrency(Currency currency) {
    method getPeriod (line 47) | public TimePeriod getPeriod() {
    method setPeriod (line 51) | public void setPeriod(TimePeriod period) {

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/Saving.java
  class Saving (line 6) | public class Saving {
    method getAmount (line 23) | public BigDecimal getAmount() {
    method setAmount (line 27) | public void setAmount(BigDecimal amount) {
    method getCurrency (line 31) | public Currency getCurrency() {
    method setCurrency (line 35) | public void setCurrency(Currency currency) {
    method getInterest (line 39) | public BigDecimal getInterest() {
    method setInterest (line 43) | public void setInterest(BigDecimal interest) {
    method getDeposit (line 47) | public Boolean getDeposit() {
    method setDeposit (line 51) | public void setDeposit(Boolean deposit) {
    method getCapitalization (line 55) | public Boolean getCapitalization() {
    method setCapitalization (line 59) | public void setCapitalization(Boolean capitalization) {

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/TimePeriod.java
  type TimePeriod (line 5) | public enum TimePeriod {
    method TimePeriod (line 11) | TimePeriod(double baseRatio) {
    method getBaseRatio (line 15) | public BigDecimal getBaseRatio() {
    method getBase (line 19) | public static TimePeriod getBase() {

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/timeseries/DataPoint.java
  class DataPoint (line 15) | @Document(collection = "datapoints")
    method getId (line 29) | public DataPointId getId() {
    method setId (line 33) | public void setId(DataPointId id) {
    method getIncomes (line 37) | public Set<ItemMetric> getIncomes() {
    method setIncomes (line 41) | public void setIncomes(Set<ItemMetric> incomes) {
    method getExpenses (line 45) | public Set<ItemMetric> getExpenses() {
    method setExpenses (line 49) | public void setExpenses(Set<ItemMetric> expenses) {
    method getStatistics (line 53) | public Map<StatisticMetric, BigDecimal> getStatistics() {
    method setStatistics (line 57) | public void setStatistics(Map<StatisticMetric, BigDecimal> statistics) {
    method getRates (line 61) | public Map<Currency, BigDecimal> getRates() {
    method setRates (line 65) | public void setRates(Map<Currency, BigDecimal> rates) {

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/timeseries/DataPointId.java
  class DataPointId (line 6) | public class DataPointId implements Serializable {
    method DataPointId (line 14) | public DataPointId(String account, Date date) {
    method getAccount (line 19) | public String getAccount() {
    method getDate (line 23) | public Date getDate() {
    method toString (line 27) | @Override

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/timeseries/ItemMetric.java
  class ItemMetric (line 12) | public class ItemMetric {
    method ItemMetric (line 18) | public ItemMetric(String title, BigDecimal amount) {
    method getTitle (line 23) | public String getTitle() {
    method getAmount (line 27) | public BigDecimal getAmount() {
    method equals (line 31) | @Override
    method hashCode (line 42) | @Override

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/domain/timeseries/StatisticMetric.java
  type StatisticMetric (line 3) | public enum StatisticMetric {

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/repository/DataPointRepository.java
  type DataPointRepository (line 10) | @Repository
    method findByIdAccount (line 13) | List<DataPoint> findByIdAccount(String account);

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/repository/converter/DataPointIdReaderConverter.java
  class DataPointIdReaderConverter (line 10) | @Component
    method convert (line 13) | @Override

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/repository/converter/DataPointIdWriterConverter.java
  class DataPointIdWriterConverter (line 9) | @Component
    method convert (line 14) | @Override

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/service/ExchangeRatesService.java
  type ExchangeRatesService (line 8) | public interface ExchangeRatesService {
    method getCurrentRates (line 16) | Map<Currency, BigDecimal> getCurrentRates();
    method convert (line 26) | BigDecimal convert(Currency from, Currency to, BigDecimal amount);

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/service/ExchangeRatesServiceImpl.java
  class ExchangeRatesServiceImpl (line 18) | @Service
    method getCurrentRates (line 31) | @Override
    method convert (line 49) | @Override

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/service/StatisticsService.java
  type StatisticsService (line 8) | public interface StatisticsService {
    method findByAccountName (line 16) | List<DataPoint> findByAccountName(String accountName);
    method save (line 28) | DataPoint save(String accountName, Account account);

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/service/StatisticsServiceImpl.java
  class StatisticsServiceImpl (line 27) | @Service
    method findByAccountName (line 41) | @Override
    method save (line 50) | @Override
    method createStatisticMetrics (line 80) | private Map<StatisticMetric, BigDecimal> createStatisticMetrics(Set<It...
    method createItemMetric (line 103) | private ItemMetric createItemMetric(Item item) {

FILE: statistics-service/src/main/java/com/piggymetrics/statistics/service/security/CustomUserInfoTokenServices.java
  class CustomUserInfoTokenServices (line 29) | public class CustomUserInfoTokenServices implements ResourceServerTokenS...
    method CustomUserInfoTokenServices (line 46) | public CustomUserInfoTokenServices(String userInfoEndpointUrl, String ...
    method setTokenType (line 51) | public void setTokenType(String tokenType) {
    method setRestTemplate (line 55) | public void setRestTemplate(OAuth2RestOperations restTemplate) {
    method setAuthoritiesExtractor (line 59) | public void setAuthoritiesExtractor(AuthoritiesExtractor authoritiesEx...
    method loadAuthentication (line 63) | @Override
    method extractAuthentication (line 74) | private OAuth2Authentication extractAuthentication(Map<String, Object>...
    method getPrincipal (line 85) | private Object getPrincipal(Map<String, Object> map) {
    method getRequest (line 94) | @SuppressWarnings({ "unchecked" })
    method readAccessToken (line 106) | @Override
    method getMap (line 111) | @SuppressWarnings({ "unchecked" })

FILE: statistics-service/src/test/java/com/piggymetrics/statistics/StatisticsServiceApplicationTests.java
  class StatisticsServiceApplicationTests (line 8) | @RunWith(SpringRunner.class)
    method contextLoads (line 12) | @Test

FILE: statistics-service/src/test/java/com/piggymetrics/statistics/client/ExchangeRatesClientTest.java
  class ExchangeRatesClientTest (line 16) | @RunWith(SpringRunner.class)
    method shouldRetrieveExchangeRates (line 23) | @Test
    method shouldRetrieveExchangeRatesForSpecifiedCurrency (line 37) | @Test

FILE: statistics-service/src/test/java/com/piggymetrics/statistics/controller/StatisticsControllerTest.java
  class StatisticsControllerTest (line 39) | @RunWith(SpringRunner.class)
    method setup (line 53) | @Before
    method shouldGetStatisticsByAccountName (line 59) | @Test
    method shouldGetCurrentAccountStatistics (line 73) | @Test
    method shouldSaveAccountStatistics (line 87) | @Test

FILE: statistics-service/src/test/java/com/piggymetrics/statistics/repository/DataPointRepositoryTest.java
  class DataPointRepositoryTest (line 21) | @RunWith(SpringRunner.class)
    method shouldSaveDataPoint (line 28) | @Test
    method shouldRewriteDataPointWithinADay (line 58) | @Test

FILE: statistics-service/src/test/java/com/piggymetrics/statistics/service/ExchangeRatesServiceImplTest.java
  class ExchangeRatesServiceImplTest (line 20) | public class ExchangeRatesServiceImplTest {
    method setup (line 28) | @Before
    method shouldReturnCurrentRatesWhenContainerIsEmptySoFar (line 33) | @Test
    method shouldNotRequestRatesWhenTodaysContainerAlreadyExists (line 52) | @Test
    method shouldConvertCurrency (line 72) | @Test
    method shouldFailToConvertWhenAmountIsNull (line 91) | @Test(expected = IllegalArgumentException.class)

FILE: statistics-service/src/test/java/com/piggymetrics/statistics/service/StatisticsServiceImplTest.java
  class StatisticsServiceImplTest (line 36) | public class StatisticsServiceImplTest {
    method setup (line 47) | @Before
    method shouldFindDataPointListByAccountName (line 52) | @Test
    method shouldFailToFindDataPointWhenAccountNameIsNull (line 61) | @Test(expected = IllegalArgumentException.class)
    method shouldFailToFindDataPointWhenAccountNameIsEmpty (line 66) | @Test(expected = IllegalArgumentException.class)
    method shouldSaveDataPoint (line 71) | @Test

FILE: turbine-stream-service/src/main/java/com/piggymetrics/turbine/TurbineStreamServiceApplication.java
  class TurbineStreamServiceApplication (line 8) | @SpringBootApplication
    method main (line 13) | public static void main(String[] args) {

FILE: turbine-stream-service/src/test/java/com/piggymetrics/turbine/TurbineStreamServiceApplicationTests.java
  class TurbineStreamServiceApplicationTests (line 8) | @RunWith(SpringRunner.class)
    method contextLoads (line 12) | @Test
Condensed preview — 166 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (515K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report-or-feature-request.md",
    "chars": 640,
    "preview": "---\nname: Bug report or feature request\nabout: Suggest an idea or report a bug\n\n---\n\n- If you have troubles to run the c"
  },
  {
    "path": ".gitignore",
    "chars": 121,
    "preview": "# Intellij\n.idea/\n*.iml\n*.iws\n\n# Mac\n.DS_Store\n\n# Maven\nlog/\ntarget/\n\n# Eclipse\n**/*.project\n**/*.classpath\n**/*.setting"
  },
  {
    "path": ".travis.yml",
    "chars": 4647,
    "preview": "dist: trusty\nsudo: required\n\nservices:\n  - docker\n\nlanguage: java\njdk: oraclejdk8\n\nenv:\n  global:\n    - secure: \"GeONVsT"
  },
  {
    "path": "LICENCE",
    "chars": 1107,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Alexander Lukyanchikov, http://sqshq.com\n\nPermission is hereby granted, free o"
  },
  {
    "path": "README.md",
    "chars": 19095,
    "preview": "[![Build Status](https://travis-ci.org/sqshq/PiggyMetrics.svg?branch=master)](https://travis-ci.org/sqshq/PiggyMetrics)\n"
  },
  {
    "path": "account-service/Dockerfile",
    "chars": 181,
    "preview": "FROM java:8-jre\nMAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>\n\nADD ./target/account-service.jar /app/\nCMD [\"java\","
  },
  {
    "path": "account-service/pom.xml",
    "chars": 3427,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/AccountApplication.java",
    "chars": 870,
    "preview": "package com.piggymetrics.account;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.au"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/client/AuthServiceClient.java",
    "chars": 536,
    "preview": "package com.piggymetrics.account.client;\n\nimport com.piggymetrics.account.domain.User;\nimport org.springframework.cloud."
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/client/StatisticsServiceClient.java",
    "chars": 737,
    "preview": "package com.piggymetrics.account.client;\n\nimport com.piggymetrics.account.domain.Account;\nimport org.springframework.clo"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/client/StatisticsServiceClientFallback.java",
    "chars": 598,
    "preview": "package com.piggymetrics.account.client;\n\nimport com.piggymetrics.account.domain.Account;\nimport org.slf4j.Logger;\nimpor"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/config/ResourceServerConfig.java",
    "chars": 2483,
    "preview": "package com.piggymetrics.account.config;\n\nimport com.piggymetrics.account.service.security.CustomUserInfoTokenServices;\n"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/controller/AccountController.java",
    "chars": 1350,
    "preview": "package com.piggymetrics.account.controller;\n\nimport com.piggymetrics.account.domain.Account;\nimport com.piggymetrics.ac"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/controller/ErrorHandler.java",
    "chars": 756,
    "preview": "package com.piggymetrics.account.controller;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.spring"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/domain/Account.java",
    "chars": 1444,
    "preview": "package com.piggymetrics.account.domain;\n\nimport org.codehaus.jackson.annotate.JsonIgnoreProperties;\nimport org.hibernat"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/domain/Currency.java",
    "chars": 141,
    "preview": "package com.piggymetrics.account.domain;\n\npublic enum Currency {\n\n\tUSD, EUR, RUB;\n\n\tpublic static Currency getDefault() "
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/domain/Item.java",
    "chars": 1007,
    "preview": "package com.piggymetrics.account.domain;\n\nimport org.hibernate.validator.constraints.Length;\n\nimport javax.validation.co"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/domain/Saving.java",
    "chars": 1033,
    "preview": "package com.piggymetrics.account.domain;\n\nimport javax.validation.constraints.NotNull;\nimport java.math.BigDecimal;\n\npub"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/domain/TimePeriod.java",
    "chars": 104,
    "preview": "package com.piggymetrics.account.domain;\n\npublic enum TimePeriod {\n\n\tYEAR, QUARTER, MONTH, DAY, HOUR\n\n}\n"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/domain/User.java",
    "chars": 552,
    "preview": "package com.piggymetrics.account.domain;\n\nimport org.hibernate.validator.constraints.Length;\n\nimport javax.validation.co"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/repository/AccountRepository.java",
    "chars": 331,
    "preview": "package com.piggymetrics.account.repository;\n\nimport com.piggymetrics.account.domain.Account;\nimport org.springframework"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/service/AccountService.java",
    "chars": 726,
    "preview": "package com.piggymetrics.account.service;\n\nimport com.piggymetrics.account.domain.Account;\nimport com.piggymetrics.accou"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/service/AccountServiceImpl.java",
    "chars": 2435,
    "preview": "package com.piggymetrics.account.service;\n\nimport com.piggymetrics.account.client.AuthServiceClient;\nimport com.piggymet"
  },
  {
    "path": "account-service/src/main/java/com/piggymetrics/account/service/security/CustomUserInfoTokenServices.java",
    "chars": 5494,
    "preview": "package com.piggymetrics.account.service.security;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.log"
  },
  {
    "path": "account-service/src/main/resources/bootstrap.yml",
    "chars": 186,
    "preview": "spring:\n  application:\n    name: account-service\n  cloud:\n    config:\n      uri: http://config:8888\n      fail-fast: tru"
  },
  {
    "path": "account-service/src/test/java/com/piggymetrics/account/AccountServiceApplicationTests.java",
    "chars": 350,
    "preview": "package com.piggymetrics.account;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.bo"
  },
  {
    "path": "account-service/src/test/java/com/piggymetrics/account/client/StatisticsServiceClientFallbackTest.java",
    "chars": 1146,
    "preview": "package com.piggymetrics.account.client;\n\nimport com.piggymetrics.account.domain.Account;\nimport org.junit.Before;\nimpor"
  },
  {
    "path": "account-service/src/test/java/com/piggymetrics/account/controller/AccountControllerTest.java",
    "chars": 4620,
    "preview": "package com.piggymetrics.account.controller;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.google.comm"
  },
  {
    "path": "account-service/src/test/java/com/piggymetrics/account/repository/AccountRepositoryTest.java",
    "chars": 2380,
    "preview": "package com.piggymetrics.account.repository;\n\nimport com.piggymetrics.account.domain.Account;\nimport com.piggymetrics.ac"
  },
  {
    "path": "account-service/src/test/java/com/piggymetrics/account/service/AccountServiceTest.java",
    "chars": 5238,
    "preview": "package com.piggymetrics.account.service;\n\nimport com.piggymetrics.account.client.AuthServiceClient;\nimport com.piggymet"
  },
  {
    "path": "account-service/src/test/resources/application.yml",
    "chars": 71,
    "preview": "spring:\n  data:\n    mongodb:\n      database: piggymetrics\n      port: 0"
  },
  {
    "path": "account-service/src/test/resources/bootstrap.yml",
    "chars": 36,
    "preview": "eureka:\n  client:\n    enabled: false"
  },
  {
    "path": "auth-service/Dockerfile",
    "chars": 175,
    "preview": "FROM java:8-jre\nMAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>\n\nADD ./target/auth-service.jar /app/\nCMD [\"java\", \"-"
  },
  {
    "path": "auth-service/pom.xml",
    "chars": 2780,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "auth-service/src/main/java/com/piggymetrics/auth/AuthApplication.java",
    "chars": 683,
    "preview": "package com.piggymetrics.auth;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoc"
  },
  {
    "path": "auth-service/src/main/java/com/piggymetrics/auth/config/OAuth2AuthorizationConfig.java",
    "chars": 3449,
    "preview": "package com.piggymetrics.auth.config;\n\nimport com.piggymetrics.auth.service.security.MongoUserDetailsService;\nimport org"
  },
  {
    "path": "auth-service/src/main/java/com/piggymetrics/auth/config/WebSecurityConfig.java",
    "chars": 1563,
    "preview": "package com.piggymetrics.auth.config;\n\nimport com.piggymetrics.auth.service.security.MongoUserDetailsService;\nimport org"
  },
  {
    "path": "auth-service/src/main/java/com/piggymetrics/auth/controller/UserController.java",
    "chars": 1015,
    "preview": "package com.piggymetrics.auth.controller;\n\nimport com.piggymetrics.auth.domain.User;\nimport com.piggymetrics.auth.servic"
  },
  {
    "path": "auth-service/src/main/java/com/piggymetrics/auth/domain/User.java",
    "chars": 1070,
    "preview": "package com.piggymetrics.auth.domain;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.mo"
  },
  {
    "path": "auth-service/src/main/java/com/piggymetrics/auth/repository/UserRepository.java",
    "chars": 281,
    "preview": "package com.piggymetrics.auth.repository;\n\nimport com.piggymetrics.auth.domain.User;\nimport org.springframework.data.rep"
  },
  {
    "path": "auth-service/src/main/java/com/piggymetrics/auth/service/UserService.java",
    "chars": 143,
    "preview": "package com.piggymetrics.auth.service;\n\nimport com.piggymetrics.auth.domain.User;\n\npublic interface UserService {\n\n\tvoid"
  },
  {
    "path": "auth-service/src/main/java/com/piggymetrics/auth/service/UserServiceImpl.java",
    "chars": 1110,
    "preview": "package com.piggymetrics.auth.service;\n\nimport com.piggymetrics.auth.domain.User;\nimport com.piggymetrics.auth.repositor"
  },
  {
    "path": "auth-service/src/main/java/com/piggymetrics/auth/service/security/MongoUserDetailsService.java",
    "chars": 768,
    "preview": "package com.piggymetrics.auth.service.security;\n\nimport com.piggymetrics.auth.repository.UserRepository;\nimport org.spri"
  },
  {
    "path": "auth-service/src/main/resources/bootstrap.yml",
    "chars": 183,
    "preview": "spring:\n  application:\n    name: auth-service\n  cloud:\n    config:\n      uri: http://config:8888\n      fail-fast: true\n "
  },
  {
    "path": "auth-service/src/test/java/com/piggymetrics/auth/AuthServiceApplicationTests.java",
    "chars": 343,
    "preview": "package com.piggymetrics.auth;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot."
  },
  {
    "path": "auth-service/src/test/java/com/piggymetrics/auth/controller/UserControllerTest.java",
    "chars": 2262,
    "preview": "package com.piggymetrics.auth.controller;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.piggymetrics.a"
  },
  {
    "path": "auth-service/src/test/java/com/piggymetrics/auth/repository/UserRepositoryTest.java",
    "chars": 1207,
    "preview": "package com.piggymetrics.auth.repository;\n\nimport com.piggymetrics.auth.domain.User;\nimport com.piggymetrics.auth.servic"
  },
  {
    "path": "auth-service/src/test/java/com/piggymetrics/auth/service/UserServiceTest.java",
    "chars": 1059,
    "preview": "package com.piggymetrics.auth.service;\n\nimport com.piggymetrics.auth.domain.User;\nimport com.piggymetrics.auth.repositor"
  },
  {
    "path": "auth-service/src/test/java/com/piggymetrics/auth/service/security/MongoUserDetailsServiceTest.java",
    "chars": 1216,
    "preview": "package com.piggymetrics.auth.service.security;\n\nimport com.piggymetrics.auth.domain.User;\nimport com.piggymetrics.auth."
  },
  {
    "path": "auth-service/src/test/resources/application.yml",
    "chars": 71,
    "preview": "spring:\n  data:\n    mongodb:\n      database: piggymetrics\n      port: 0"
  },
  {
    "path": "auth-service/src/test/resources/bootstrap.yml",
    "chars": 36,
    "preview": "eureka:\n  client:\n    enabled: false"
  },
  {
    "path": "config/Dockerfile",
    "chars": 265,
    "preview": "FROM java:8-jre\nMAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>\n\nADD ./target/config.jar /app/\nCMD [\"java\", \"-Xmx200"
  },
  {
    "path": "config/pom.xml",
    "chars": 1147,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "config/src/main/java/com/piggymetrics/config/ConfigApplication.java",
    "chars": 402,
    "preview": "package com.piggymetrics.config;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.aut"
  },
  {
    "path": "config/src/main/java/com/piggymetrics/config/SecurityConfig.java",
    "chars": 721,
    "preview": "package com.piggymetrics.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframewor"
  },
  {
    "path": "config/src/main/resources/application.yml",
    "chars": 225,
    "preview": "spring:\n  cloud:\n    config:\n      server:\n        native:\n          search-locations: classpath:/shared\n  profiles:\n   "
  },
  {
    "path": "config/src/main/resources/shared/account-service.yml",
    "chars": 491,
    "preview": "security:\n  oauth2:\n    client:\n      clientId: account-service\n      clientSecret: ${ACCOUNT_SERVICE_PASSWORD}\n      ac"
  },
  {
    "path": "config/src/main/resources/shared/application.yml",
    "chars": 447,
    "preview": "logging:\n  level:\n    org.springframework.security: INFO\n\nhystrix:\n  command:\n    default:\n      execution:\n        isol"
  },
  {
    "path": "config/src/main/resources/shared/auth-service.yml",
    "chars": 214,
    "preview": "spring:\n  data:\n    mongodb:\n      host: auth-mongodb\n      username: user\n      password: ${MONGODB_PASSWORD}\n      dat"
  },
  {
    "path": "config/src/main/resources/shared/gateway.yml",
    "chars": 885,
    "preview": "hystrix:\n  command:\n    default:\n      execution:\n        isolation:\n          thread:\n            timeoutInMilliseconds"
  },
  {
    "path": "config/src/main/resources/shared/monitoring.yml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "config/src/main/resources/shared/notification-service.yml",
    "chars": 1213,
    "preview": "security:\n  oauth2:\n    client:\n      clientId: notification-service\n      clientSecret: ${NOTIFICATION_SERVICE_PASSWORD"
  },
  {
    "path": "config/src/main/resources/shared/registry.yml",
    "chars": 20,
    "preview": "server:\n  port: 8761"
  },
  {
    "path": "config/src/main/resources/shared/statistics-service.yml",
    "chars": 512,
    "preview": "security:\n  oauth2:\n    client:\n      clientId: statistics-service\n      clientSecret: ${STATISTICS_SERVICE_PASSWORD}\n  "
  },
  {
    "path": "config/src/main/resources/shared/turbine-stream-service.yml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docker-compose.dev.yml",
    "chars": 884,
    "preview": "version: '2.1'\nservices:\n  rabbitmq:\n    ports:\n      - 5672:5672\n\n  config:\n    build: config\n    ports:\n      - 8888:8"
  },
  {
    "path": "docker-compose.yml",
    "chars": 4342,
    "preview": "version: '2.1'\nservices:\n  rabbitmq:\n    image: rabbitmq:3-management\n    restart: always\n    ports:\n      - 15672:15672"
  },
  {
    "path": "gateway/Dockerfile",
    "chars": 165,
    "preview": "FROM java:8-jre\nMAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>\n\nADD ./target/gateway.jar /app/\nCMD [\"java\", \"-Xmx20"
  },
  {
    "path": "gateway/pom.xml",
    "chars": 1681,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "gateway/src/main/java/com/piggymetrics/gateway/GatewayApplication.java",
    "chars": 494,
    "preview": "package com.piggymetrics.gateway;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.au"
  },
  {
    "path": "gateway/src/main/resources/bootstrap.yml",
    "chars": 178,
    "preview": "spring:\n  application:\n    name: gateway\n  cloud:\n    config:\n      uri: http://config:8888\n      fail-fast: true\n      "
  },
  {
    "path": "gateway/src/main/resources/static/attribution.html",
    "chars": 1442,
    "preview": "<!DOCTYPE html>\n\n<htmL>\n<head>\n  <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n  <meta name=\"vie"
  },
  {
    "path": "gateway/src/main/resources/static/css/animation.css",
    "chars": 12471,
    "preview": "/* ZOOM AVATAR */\n@-webkit-keyframes zoomavatar {\n\t0% {\n\t\t-webkit-transform: scale(0.1);\n\t}\n\t60% {\n\t\t-webkit-transform: "
  },
  {
    "path": "gateway/src/main/resources/static/css/launch.css",
    "chars": 20105,
    "preview": "#createaccount, #enter, #secondenter, #info, #backlogin, #backpassword, #plusavatar, .columnimage  {\n\tbackground: url(\"."
  },
  {
    "path": "gateway/src/main/resources/static/css/style.css",
    "chars": 56249,
    "preview": "@font-face {\n\tfont-family: 'Museo-100';\n\tsrc: url('../fonts/museo-100/museo-100.eot');\n\tsrc: local('@%@'),\n\turl('../font"
  },
  {
    "path": "gateway/src/main/resources/static/index.html",
    "chars": 32161,
    "preview": "<!DOCTYPE html>\n<htmL>\n<head>\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n    <meta name=\""
  },
  {
    "path": "gateway/src/main/resources/static/js/dashboard.js",
    "chars": 26394,
    "preview": "/**\n * KNOB circles initialization\n */\n\n$(\"#inner-circle\").knob({\n\t\"readOnly\": true,\n\t\"width\": 223,\n\t\"height\": 223,\n\t\"th"
  },
  {
    "path": "gateway/src/main/resources/static/js/launch.js",
    "chars": 2052,
    "preview": "var global = {\n    mobileClient: false,\n    savePermit: true,\n    usd: 0,\n    eur: 0\n};\n\n/**\n * Oauth2\n */\n\nfunction req"
  },
  {
    "path": "gateway/src/main/resources/static/js/lib/extrascripts.js",
    "chars": 60295,
    "preview": "/*\n* autoNumeric.js\n* @author: Bob Knothe\n* @author: Sokolov Yura\n*\n* Created by Robert J. Knothe on 2010-10-25. Please "
  },
  {
    "path": "gateway/src/main/resources/static/js/lib/touchscreens.js",
    "chars": 18606,
    "preview": "/*\n * jQuery.fastClick.js\n *\n * Work around the 300ms delay for the click event in some mobile browsers.\n *\n * @license "
  },
  {
    "path": "gateway/src/main/resources/static/js/login.js",
    "chars": 5854,
    "preview": "/**\r * Registration form\r */\r\r$('#signup').submit(function(e) {\r\r    e.preventDefault();\r\r    var username = $(\"input[id"
  },
  {
    "path": "gateway/src/main/resources/static/js/main.js",
    "chars": 32994,
    "preview": "var user = {},\n    savings = {},\n    incomes = {},\n    expenses = {};\n\nfunction initAccount(account) {\n    user = new Us"
  },
  {
    "path": "gateway/src/test/java/com/piggymetrics/gateway/GatewayApplicationTests.java",
    "chars": 376,
    "preview": "package com.piggymetrics.gateway;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.bo"
  },
  {
    "path": "gateway/src/test/resources/bootstrap.yml",
    "chars": 36,
    "preview": "eureka:\n  client:\n    enabled: false"
  },
  {
    "path": "mongodb/Dockerfile",
    "chars": 435,
    "preview": "FROM mongo:3\nMAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>\n\nADD init.sh /init.sh\nADD ./dump /\n\nRUN \\\n chmod +x /in"
  },
  {
    "path": "mongodb/dump/account-service-dump.js",
    "chars": 1986,
    "preview": "/**\n * Creates pre-filled demo account\n */\n\nprint('dump start');\n\ndb.accounts.update(\n    { \"_id\": \"demo\" },\n    {\n    \""
  },
  {
    "path": "mongodb/init.sh",
    "chars": 847,
    "preview": "#!/bin/bash\nif test -z \"$MONGODB_PASSWORD\"; then\n    echo \"MONGODB_PASSWORD not defined\"\n    exit 1\nfi\n\nauth=\"-u user -p"
  },
  {
    "path": "monitoring/Dockerfile",
    "chars": 171,
    "preview": "FROM java:8-jre\nMAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>\n\nADD ./target/monitoring.jar /app/\nCMD [\"java\", \"-Xm"
  },
  {
    "path": "monitoring/pom.xml",
    "chars": 1288,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "monitoring/src/main/java/com/piggymetrics/monitoring/MonitoringApplication.java",
    "chars": 434,
    "preview": "package com.piggymetrics.monitoring;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot"
  },
  {
    "path": "monitoring/src/main/resources/bootstrap.yml",
    "chars": 180,
    "preview": "spring:\n  application:\n    name: monitoring\n  cloud:\n    config:\n      uri: http://config:8888\n      fail-fast: true\n   "
  },
  {
    "path": "monitoring/src/test/java/com/piggymetrics/monitoring/MonitoringApplicationTests.java",
    "chars": 348,
    "preview": "package com.piggymetrics.monitoring;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework"
  },
  {
    "path": "monitoring/src/test/resources/bootstrap.yml",
    "chars": 36,
    "preview": "eureka:\n  client:\n    enabled: false"
  },
  {
    "path": "notification-service/Dockerfile",
    "chars": 191,
    "preview": "FROM java:8-jre\nMAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>\n\nADD ./target/notification-service.jar /app/\nCMD [\"j"
  },
  {
    "path": "notification-service/pom.xml",
    "chars": 3431,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/NotificationServiceApplication.java",
    "chars": 1502,
    "preview": "package com.piggymetrics.notification;\n\nimport com.piggymetrics.notification.repository.converter.FrequencyReaderConvert"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/client/AccountServiceClient.java",
    "chars": 615,
    "preview": "package com.piggymetrics.notification.client;\n\nimport org.springframework.cloud.openfeign.FeignClient;\nimport org.spring"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/config/ResourceServerConfig.java",
    "chars": 1537,
    "preview": "package com.piggymetrics.notification.config;\n\nimport feign.RequestInterceptor;\nimport org.springframework.boot.context."
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/controller/RecipientController.java",
    "chars": 1134,
    "preview": "package com.piggymetrics.notification.controller;\n\nimport com.piggymetrics.notification.domain.Recipient;\nimport com.pig"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/domain/Frequency.java",
    "chars": 450,
    "preview": "package com.piggymetrics.notification.domain;\n\nimport java.util.stream.Stream;\n\npublic enum Frequency {\n\n\tWEEKLY(7), MON"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/domain/NotificationSettings.java",
    "chars": 672,
    "preview": "package com.piggymetrics.notification.domain;\n\nimport javax.validation.constraints.NotNull;\nimport java.util.Date;\n\npubl"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/domain/NotificationType.java",
    "chars": 604,
    "preview": "package com.piggymetrics.notification.domain;\n\npublic enum NotificationType {\n\n\tBACKUP(\"backup.email.subject\", \"backup.e"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/domain/Recipient.java",
    "chars": 1234,
    "preview": "package com.piggymetrics.notification.domain;\n\nimport org.hibernate.validator.constraints.Email;\nimport org.springframew"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/repository/RecipientRepository.java",
    "chars": 1006,
    "preview": "package com.piggymetrics.notification.repository;\n\nimport com.piggymetrics.notification.domain.Recipient;\nimport org.spr"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/repository/converter/FrequencyReaderConverter.java",
    "chars": 413,
    "preview": "package com.piggymetrics.notification.repository.converter;\n\nimport com.piggymetrics.notification.domain.Frequency;\nimpo"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/repository/converter/FrequencyWriterConverter.java",
    "chars": 413,
    "preview": "package com.piggymetrics.notification.repository.converter;\n\nimport com.piggymetrics.notification.domain.Frequency;\nimpo"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/service/EmailService.java",
    "chars": 383,
    "preview": "package com.piggymetrics.notification.service;\n\nimport com.piggymetrics.notification.domain.NotificationType;\nimport com"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/service/EmailServiceImpl.java",
    "chars": 1839,
    "preview": "package com.piggymetrics.notification.service;\n\nimport com.piggymetrics.notification.domain.NotificationType;\nimport com"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/service/NotificationService.java",
    "chars": 157,
    "preview": "package com.piggymetrics.notification.service;\n\npublic interface NotificationService {\n\n\tvoid sendBackupNotifications();"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/service/NotificationServiceImpl.java",
    "chars": 2099,
    "preview": "package com.piggymetrics.notification.service;\n\nimport com.piggymetrics.notification.client.AccountServiceClient;\nimport"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/service/RecipientService.java",
    "chars": 983,
    "preview": "package com.piggymetrics.notification.service;\n\nimport com.piggymetrics.notification.domain.NotificationType;\nimport com"
  },
  {
    "path": "notification-service/src/main/java/com/piggymetrics/notification/service/RecipientServiceImpl.java",
    "chars": 1823,
    "preview": "package com.piggymetrics.notification.service;\n\nimport com.piggymetrics.notification.domain.NotificationType;\nimport com"
  },
  {
    "path": "notification-service/src/main/resources/bootstrap.yml",
    "chars": 190,
    "preview": "spring:\n  application:\n    name: notification-service\n  cloud:\n    config:\n      uri: http://config:8888\n      fail-fast"
  },
  {
    "path": "notification-service/src/test/java/com/piggymetrics/notification/NotificationServiceApplicationTests.java",
    "chars": 359,
    "preview": "package com.piggymetrics.notification;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframewo"
  },
  {
    "path": "notification-service/src/test/java/com/piggymetrics/notification/controller/RecipientControllerTest.java",
    "chars": 3235,
    "preview": "package com.piggymetrics.notification.controller;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.google"
  },
  {
    "path": "notification-service/src/test/java/com/piggymetrics/notification/repository/RecipientRepositoryTest.java",
    "chars": 5399,
    "preview": "package com.piggymetrics.notification.repository;\n\nimport com.google.common.collect.ImmutableMap;\nimport com.piggymetric"
  },
  {
    "path": "notification-service/src/test/java/com/piggymetrics/notification/service/EmailServiceImplTest.java",
    "chars": 2665,
    "preview": "package com.piggymetrics.notification.service;\n\nimport com.piggymetrics.notification.domain.NotificationType;\nimport com"
  },
  {
    "path": "notification-service/src/test/java/com/piggymetrics/notification/service/NotificationServiceImplTest.java",
    "chars": 2845,
    "preview": "package com.piggymetrics.notification.service;\n\nimport com.google.common.collect.ImmutableList;\nimport com.piggymetrics."
  },
  {
    "path": "notification-service/src/test/java/com/piggymetrics/notification/service/RecipientServiceImplTest.java",
    "chars": 3691,
    "preview": "package com.piggymetrics.notification.service;\n\nimport com.google.common.collect.ImmutableList;\nimport com.google.common"
  },
  {
    "path": "notification-service/src/test/resources/application.yml",
    "chars": 798,
    "preview": "remind:\n  cron: 0 0 0 * * *\n  email:\n    text: \"Hey, {0}! We''ve missed you here on PiggyMetrics. It''s time to check yo"
  },
  {
    "path": "notification-service/src/test/resources/bootstrap.yml",
    "chars": 36,
    "preview": "eureka:\n  client:\n    enabled: false"
  },
  {
    "path": "pom.xml",
    "chars": 1472,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLo"
  },
  {
    "path": "registry/Dockerfile",
    "chars": 167,
    "preview": "FROM java:8-jre\nMAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>\n\nADD ./target/registry.jar /app/\nCMD [\"java\", \"-Xmx2"
  },
  {
    "path": "registry/pom.xml",
    "chars": 1312,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "registry/src/main/java/com/piggymetrics/registry/RegistryApplication.java",
    "chars": 416,
    "preview": "package com.piggymetrics.registry;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.a"
  },
  {
    "path": "registry/src/main/resources/bootstrap.yml",
    "chars": 339,
    "preview": "spring:\n  application:\n    name: registry\n  cloud:\n    config:\n      uri: http://config:8888\n      fail-fast: true\n     "
  },
  {
    "path": "statistics-service/Dockerfile",
    "chars": 187,
    "preview": "FROM java:8-jre\nMAINTAINER Alexander Lukyanchikov <sqshq@sqshq.com>\n\nADD ./target/statistics-service.jar /app/\nCMD [\"jav"
  },
  {
    "path": "statistics-service/pom.xml",
    "chars": 3424,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/StatisticsApplication.java",
    "chars": 1729,
    "preview": "package com.piggymetrics.statistics;\n\nimport com.piggymetrics.statistics.repository.converter.DataPointIdReaderConverter"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/client/ExchangeRatesClient.java",
    "chars": 694,
    "preview": "package com.piggymetrics.statistics.client;\n\nimport com.piggymetrics.statistics.domain.Currency;\nimport com.piggymetrics"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/client/ExchangeRatesClientFallback.java",
    "chars": 610,
    "preview": "package com.piggymetrics.statistics.client;\n\nimport com.piggymetrics.statistics.domain.Currency;\nimport com.piggymetrics"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/config/ResourceServerConfig.java",
    "chars": 1059,
    "preview": "package com.piggymetrics.statistics.config;\n\nimport com.piggymetrics.statistics.service.security.CustomUserInfoTokenServ"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/controller/StatisticsController.java",
    "chars": 1389,
    "preview": "package com.piggymetrics.statistics.controller;\n\nimport com.piggymetrics.statistics.domain.Account;\nimport com.piggymetr"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/Account.java",
    "chars": 900,
    "preview": "package com.piggymetrics.statistics.domain;\n\nimport org.codehaus.jackson.annotate.JsonIgnoreProperties;\nimport org.sprin"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/Currency.java",
    "chars": 141,
    "preview": "package com.piggymetrics.statistics.domain;\n\npublic enum Currency {\n\n\tUSD, EUR, RUB;\n\n\tpublic static Currency getBase() "
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/ExchangeRatesContainer.java",
    "chars": 912,
    "preview": "package com.piggymetrics.statistics.domain;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\nimport java."
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/Item.java",
    "chars": 871,
    "preview": "package com.piggymetrics.statistics.domain;\n\nimport org.hibernate.validator.constraints.Length;\n\nimport javax.validation"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/Saving.java",
    "chars": 1036,
    "preview": "package com.piggymetrics.statistics.domain;\n\nimport javax.validation.constraints.NotNull;\nimport java.math.BigDecimal;\n\n"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/TimePeriod.java",
    "chars": 402,
    "preview": "package com.piggymetrics.statistics.domain;\n\nimport java.math.BigDecimal;\n\npublic enum TimePeriod {\n\n\tYEAR(365.2425), QU"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/timeseries/DataPoint.java",
    "chars": 1382,
    "preview": "package com.piggymetrics.statistics.domain.timeseries;\n\nimport com.piggymetrics.statistics.domain.Currency;\nimport org.s"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/timeseries/DataPointId.java",
    "chars": 591,
    "preview": "package com.piggymetrics.statistics.domain.timeseries;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\npublic clas"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/timeseries/ItemMetric.java",
    "chars": 949,
    "preview": "package com.piggymetrics.statistics.domain.timeseries;\n\nimport com.piggymetrics.statistics.domain.Currency;\nimport com.p"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/domain/timeseries/StatisticMetric.java",
    "chars": 138,
    "preview": "package com.piggymetrics.statistics.domain.timeseries;\n\npublic enum StatisticMetric {\n\n\tINCOMES_AMOUNT, EXPENSES_AMOUNT,"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/repository/DataPointRepository.java",
    "chars": 465,
    "preview": "package com.piggymetrics.statistics.repository;\n\nimport com.piggymetrics.statistics.domain.timeseries.DataPoint;\nimport "
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/repository/converter/DataPointIdReaderConverter.java",
    "chars": 585,
    "preview": "package com.piggymetrics.statistics.repository.converter;\n\nimport com.mongodb.DBObject;\nimport com.piggymetrics.statisti"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/repository/converter/DataPointIdWriterConverter.java",
    "chars": 640,
    "preview": "package com.piggymetrics.statistics.repository.converter;\n\nimport com.mongodb.BasicDBObject;\nimport com.mongodb.DBObject"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/service/ExchangeRatesService.java",
    "chars": 675,
    "preview": "package com.piggymetrics.statistics.service;\n\nimport com.piggymetrics.statistics.domain.Currency;\n\nimport java.math.BigD"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/service/ExchangeRatesServiceImpl.java",
    "chars": 1671,
    "preview": "package com.piggymetrics.statistics.service;\n\nimport com.google.common.collect.ImmutableMap;\nimport com.piggymetrics.sta"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/service/StatisticsService.java",
    "chars": 703,
    "preview": "package com.piggymetrics.statistics.service;\n\nimport com.piggymetrics.statistics.domain.Account;\nimport com.piggymetrics"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/service/StatisticsServiceImpl.java",
    "chars": 3469,
    "preview": "package com.piggymetrics.statistics.service;\n\nimport com.google.common.collect.ImmutableMap;\nimport com.piggymetrics.sta"
  },
  {
    "path": "statistics-service/src/main/java/com/piggymetrics/statistics/service/security/CustomUserInfoTokenServices.java",
    "chars": 5497,
    "preview": "package com.piggymetrics.statistics.service.security;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons."
  },
  {
    "path": "statistics-service/src/main/resources/bootstrap.yml",
    "chars": 188,
    "preview": "spring:\n  application:\n    name: statistics-service\n  cloud:\n    config:\n      uri: http://config:8888\n      fail-fast: "
  },
  {
    "path": "statistics-service/src/test/java/com/piggymetrics/statistics/StatisticsServiceApplicationTests.java",
    "chars": 355,
    "preview": "package com.piggymetrics.statistics;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework"
  },
  {
    "path": "statistics-service/src/test/java/com/piggymetrics/statistics/client/ExchangeRatesClientTest.java",
    "chars": 1553,
    "preview": "package com.piggymetrics.statistics.client;\n\nimport com.piggymetrics.statistics.domain.Currency;\nimport com.piggymetrics"
  },
  {
    "path": "statistics-service/src/test/java/com/piggymetrics/statistics/controller/StatisticsControllerTest.java",
    "chars": 4317,
    "preview": "package com.piggymetrics.statistics.controller;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.google.c"
  },
  {
    "path": "statistics-service/src/test/java/com/piggymetrics/statistics/repository/DataPointRepositoryTest.java",
    "chars": 2913,
    "preview": "package com.piggymetrics.statistics.repository;\n\nimport com.google.common.collect.ImmutableMap;\nimport com.google.common"
  },
  {
    "path": "statistics-service/src/test/java/com/piggymetrics/statistics/service/ExchangeRatesServiceImplTest.java",
    "chars": 2830,
    "preview": "package com.piggymetrics.statistics.service;\n\nimport com.google.common.collect.ImmutableMap;\nimport com.piggymetrics.sta"
  },
  {
    "path": "statistics-service/src/test/java/com/piggymetrics/statistics/service/StatisticsServiceImplTest.java",
    "chars": 5636,
    "preview": "package com.piggymetrics.statistics.service;\n\nimport com.google.common.collect.ImmutableList;\nimport com.google.common.c"
  },
  {
    "path": "statistics-service/src/test/resources/application.yml",
    "chars": 247,
    "preview": "hystrix:\n  command:\n    default:\n      execution:\n        isolation:\n          thread:\n            timeoutInMilliseconds"
  },
  {
    "path": "statistics-service/src/test/resources/bootstrap.yml",
    "chars": 36,
    "preview": "eureka:\n  client:\n    enabled: false"
  },
  {
    "path": "turbine-stream-service/Dockerfile",
    "chars": 186,
    "preview": "FROM java:8-jre\nMAINTAINER Chi Dov <d.chiproeng@gmail.com>\n\nADD ./target/turbine-stream-service.jar /app/\nCMD [\"java\", \""
  },
  {
    "path": "turbine-stream-service/pom.xml",
    "chars": 1653,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  },
  {
    "path": "turbine-stream-service/src/main/java/com/piggymetrics/turbine/TurbineStreamServiceApplication.java",
    "chars": 538,
    "preview": "package com.piggymetrics.turbine;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.au"
  },
  {
    "path": "turbine-stream-service/src/main/resources/bootstrap.yml",
    "chars": 192,
    "preview": "spring:\n  application:\n    name: turbine-stream-service\n  cloud:\n    config:\n      uri: http://config:8888\n      fail-fa"
  },
  {
    "path": "turbine-stream-service/src/test/java/com/piggymetrics/turbine/TurbineStreamServiceApplicationTests.java",
    "chars": 355,
    "preview": "package com.piggymetrics.turbine;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.bo"
  },
  {
    "path": "turbine-stream-service/src/test/resources/bootstrap.yml",
    "chars": 36,
    "preview": "eureka:\n  client:\n    enabled: false"
  }
]

About this extraction

This page contains the full source code of the sqshq/piggymetrics GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 166 files (455.9 KB), approximately 135.8k tokens, and a symbol index with 521 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!