From b33cdc7307547405a16bfbd32d80b2adac041cc3 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Mon, 13 Feb 2017 11:33:56 -0600 Subject: [PATCH 01/99] Adding some issue metric ideas. --- docs/metrics/Repos.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/metrics/Repos.md b/docs/metrics/Repos.md index d349207..565a95f 100644 --- a/docs/metrics/Repos.md +++ b/docs/metrics/Repos.md @@ -27,3 +27,11 @@ msr14 limitations - number of milestones - age - latest commit + + ### Regarding Issues + - Number of Issues vs last completed issue + - Number of Issues closed over a period of time + - Average of how often an issue is created + - Age of Issues + - How often a contributor comments on an issue + - Average of how often issues get commented on From 28059883753ba72748c20f7481cbb45420ff9d68 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Mon, 13 Feb 2017 14:06:55 -0600 Subject: [PATCH 02/99] Moving issue metrics to its own file --- docs/metrics/Issues.md | 9 +++++++++ docs/metrics/Repos.md | 8 -------- docs/metrics/Repos.md~ | 29 +++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 docs/metrics/Issues.md create mode 100644 docs/metrics/Repos.md~ diff --git a/docs/metrics/Issues.md b/docs/metrics/Issues.md new file mode 100644 index 0000000..da4c514 --- /dev/null +++ b/docs/metrics/Issues.md @@ -0,0 +1,9 @@ + #Metrics for Issues of Repo + + ###Issue ideas + - Number of Issues vs last completed issue + - Number of Issues closed over a period of time + - Average of how often an issue is created + - Age of Issues + - How often a contributor comments on an issue + - Average of how often issues get commented on diff --git a/docs/metrics/Repos.md b/docs/metrics/Repos.md index 565a95f..d349207 100644 --- a/docs/metrics/Repos.md +++ b/docs/metrics/Repos.md @@ -27,11 +27,3 @@ msr14 limitations - number of milestones - age - latest commit - - ### Regarding Issues - - Number of Issues vs last completed issue - - Number of Issues closed over a period of time - - Average of how often an issue is created - - Age of Issues - - How often a contributor comments on an issue - - Average of how often issues get commented on diff --git a/docs/metrics/Repos.md~ b/docs/metrics/Repos.md~ new file mode 100644 index 0000000..d349207 --- /dev/null +++ b/docs/metrics/Repos.md~ @@ -0,0 +1,29 @@ +#Some overall stats on the project + +msr14 limitations + - has no recognition of releases, tags, stars, downloads + - has an empty table: RepoMilestone + + +###From slides + - Release frequency - Unavailable in msr14 + - Number of releases - Unavailable in msr14 + - Number of downloads - Unavailable in msr14 + - number of stars - Unavailable in msr14 + - number of forks + +###More ideas + - Semantic versioning? Major version released? - Unavailable + - Date time and version of latest release - Unavailable + - travis ci stuff - parse readme of repo + - number of contributors + - numbers of watchers + - number of watchers who aren't contributors + - organizations of contributors + - project doesn't have an organization directly + - number of labels + - is a fork + - number of commits + - number of milestones + - age + - latest commit From 64e6c893bb0cf500e8119e66c61a9dbf86a1e5f1 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Mon, 13 Feb 2017 14:08:23 -0600 Subject: [PATCH 03/99] Removing extra file --- docs/metrics/Repos.md~ | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 docs/metrics/Repos.md~ diff --git a/docs/metrics/Repos.md~ b/docs/metrics/Repos.md~ deleted file mode 100644 index d349207..0000000 --- a/docs/metrics/Repos.md~ +++ /dev/null @@ -1,29 +0,0 @@ -#Some overall stats on the project - -msr14 limitations - - has no recognition of releases, tags, stars, downloads - - has an empty table: RepoMilestone - - -###From slides - - Release frequency - Unavailable in msr14 - - Number of releases - Unavailable in msr14 - - Number of downloads - Unavailable in msr14 - - number of stars - Unavailable in msr14 - - number of forks - -###More ideas - - Semantic versioning? Major version released? - Unavailable - - Date time and version of latest release - Unavailable - - travis ci stuff - parse readme of repo - - number of contributors - - numbers of watchers - - number of watchers who aren't contributors - - organizations of contributors - - project doesn't have an organization directly - - number of labels - - is a fork - - number of commits - - number of milestones - - age - - latest commit From 79ee877c0eb3a9cb239236f3999108400f5c6340 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 12 Feb 2017 20:25:40 -0600 Subject: [PATCH 04/99] Added metrics to project response. Adjust project response schema. --- docs/rest_api/Repos.md | 4 +-- repo_health/gh_commits/models/GhCommit.py | 2 +- repo_health/gh_projects/views.py | 44 +++++++++++++++++++++-- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/docs/rest_api/Repos.md b/docs/rest_api/Repos.md index 599bede..4fd1063 100644 --- a/docs/rest_api/Repos.md +++ b/docs/rest_api/Repos.md @@ -18,14 +18,14 @@ URL: "ext_ref_id": str, "deleted": int, "owner": int, + "forked_from": null or int, "contribs_count": int, "watchers_count": int, "watch_not_contribs_counts: int, "orgs_of_contribs_count": int, "labels_count": int, - "is_fork": bool, "commits_count": int, "milestones_count": int, - "age_of_latest_commit": date str + "latest_commit": date str } ``` \ No newline at end of file diff --git a/repo_health/gh_commits/models/GhCommit.py b/repo_health/gh_commits/models/GhCommit.py index 9bc1c2a..ca3771a 100644 --- a/repo_health/gh_commits/models/GhCommit.py +++ b/repo_health/gh_commits/models/GhCommit.py @@ -22,7 +22,7 @@ class GhCommit(models.Model): ) committer = models.ForeignKey( 'gh_users.GhUser', models.DO_NOTHING, - blank=True, null=True, related_name="committer" + blank=True, null=True, related_name="commits" ) project = models.ForeignKey( 'gh_projects.GhProject', models.DO_NOTHING, blank=True, null=True, diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index 10f69da..508fe15 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -12,16 +12,56 @@ from rest_framework.mixins import ListModelMixin from rest_framework.viewsets import GenericViewSet -from rest_framework.serializers import ModelSerializer +from rest_framework.serializers import ModelSerializer, SerializerMethodField from rest_framework.exceptions import NotFound from rest_framework.status import HTTP_404_NOT_FOUND +from repo_health.gh_users.models import GhUser from .models import GhProject + class GhProjectSerializer(ModelSerializer): + _contribs_count = None + _watchers_count = None + _watch_not_contribs_count = None + _orgs_of_contribs_count = None + _labels_count = None + _commits_count = None + _milestones_count = None + _latest_commit = None + + contribs_count = SerializerMethodField() + watchers_count = SerializerMethodField() + # watch_not_contribs_count = SerializerMethodField() + # commits_count = SerializerMethodField() + # milestones_count = SerializerMethodField() + # labels_count = SerializerMethodField() + # orgs_of_contribs_count = SerializerMethodField() + # commits_count = SerializerMethodField() + + + def __init__(self, *args, **kwargs): + """ + Get some statistics for repo. + """ + super().__init__(*args, **kwargs) + repo = args[0].first() + if repo is not None: + commits = repo.commits_m2m.all() | repo.commits_fk.all() + self._commits_count = commits.count() + self._contribs_count = GhUser.objects.filter(commits__in=commits).distinct().count() + # print (dir(repo)) + self._watchers_count = repo.ghwatcher_set.count() + + def get_watchers_count(self, obj): + return self._watchers_count + + def get_contribs_count(self, obj): + return self._contribs_count + class Meta: model = GhProject - exclude = ['commits_m2m', 'maintainers', 'watchers', 'url', 'forked_from'] + exclude = ['commits_m2m', 'maintainers', 'watchers', 'url',] class GhProjectViewSet(ListModelMixin, GenericViewSet): From 55b52be431b1301ae893ce7e93cd9e30de8176cc Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 13 Feb 2017 14:10:06 -0600 Subject: [PATCH 05/99] Adjust metrics. --- .gitignore | 1 + README.md | 2 +- docs/metrics/PullRequests.md | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 95e6575..6243ed2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.sqlite* *.db *.pyc +*~ .DS_Store local_settings.py node_modules diff --git a/README.md b/README.md index 97b6708..b1ae5d7 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ To start using the virtualenv, run `workon `. From inside the virtualenv and in the project root folder, run `pip install -r requirements.txt` to install the deps from the file. Note for Linux users: `sudo apt-get install libmysqlclient-dev` may need to be ran from the terminal in order for MySQL to be used with the mysqlclient dependency. A mysql_config not found error will be present when running `pip install -r requirements.txt` to signify this. -Once successful, the database is ready to be migrated. Since we are using an existing database and structure we will need fake the initial migrations that normally created the tables and columns for each Django app using models that map the Github tables. These are noted by packages beginning with `gh_`. Run this command for every package in the `repo_health` folder: `python manage.py migrate --fake-initial`. After success run `python manage.py migrate` to run any other migrations. +Once successful, the database is ready to be migrated. Since we are using an existing database and structure we will need to fake the initial migrations that normally created the tables and columns for each Django app using models that map the Github tables. These are noted by packages beginning with `gh_`. Run this command for every package in the `repo_health` folder: `python manage.py migrate --fake-initial`. After success run `python manage.py migrate` to run any other migrations. Run `python manage.py runserver` to start the built in dev server, and navigate a browser to [http://localhost:8000](http://localhost:8000) to view the index page. diff --git a/docs/metrics/PullRequests.md b/docs/metrics/PullRequests.md index b13d132..5717b62 100644 --- a/docs/metrics/PullRequests.md +++ b/docs/metrics/PullRequests.md @@ -2,7 +2,7 @@ ###From slides: - - total numer of pr + - total number of pr - total number commits - number of pr with no comment from maintainer - number of prs waiting for a response @@ -11,5 +11,7 @@ ###More ideas - organizational prs - numbers prs from outside maintainers - - total number of comments + - total number of comments on prs + - total number of comments from maintainers + - most contributing user (user with most accepted prs) From bf40a0b2b0217e92b63712bf7e9a69e0dcfc117d Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Mon, 13 Feb 2017 18:18:32 -0600 Subject: [PATCH 06/99] Added Karma/Jasmine test framework for the ui --- CONTRIBUTING.md | 5 +- README.md | 2 + repo_health/index/static/karma.conf.js | 80 +++++++++++++++++++ repo_health/index/static/package.json | 9 ++- .../src/components/search/search.spec.js | 25 ++++++ 5 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 repo_health/index/static/karma.conf.js create mode 100644 repo_health/index/static/src/components/search/search.spec.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d0b7895..52e2c80 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,9 @@ ####No external contributions are currently being accepted because this is a project for a university course. ####Guidelines -- Always checkout a branch for developing. Never push to master or dev -- Merging into master or dev requires a pull request, code review, and approval by a contributor +- Always checkout a branch for developing. Never push to master or dev. +- Write tests for all code written. +- Merging into master or dev requires a pull request, code review, and approval by a contributor. - After pull request is approved, the creator of the pull request will complete the merge unless otherwise noted. ####Contributors by Github username: diff --git a/README.md b/README.md index 97b6708..ddc0b70 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ Run `python manage.py test --keepdb` to run the tests. The `--keepdb` is import ### Frontend configuration From project root, `cd repo_health/index/static`. Run `npm install`. After successful install, [http://localhost:8000](http://localhost:8000) should display the Hello World page. +To run ui tests, run `npm test` in the `repo_health/index/static` folder. + #### Some common commands to help determine what python is being used - `which python` or `which python3` - Shows path python version. diff --git a/repo_health/index/static/karma.conf.js b/repo_health/index/static/karma.conf.js new file mode 100644 index 0000000..5d590e6 --- /dev/null +++ b/repo_health/index/static/karma.conf.js @@ -0,0 +1,80 @@ +module.exports = function(config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + + + // list of files / patterns to load in the browser + files: [ + 'node_modules/angular/angular.js', + 'node_modules/angular-ui-router/release/angular-ui-router.js', + 'node_modules/angular-mocks/angular-mocks.js', + 'src/app.js', + 'src/**/*.module.js', + 'src/**/*.service.js', + 'src/**/*.controller.js', + 'src/**/*.component.js', + 'src/**/*.spec.js', + ], + + + // list of files to exclude + exclude: [ + ], + + + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher') + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['Chrome'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: Infinity + }) +} diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index 9c16769..99ba0e0 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -4,12 +4,19 @@ "description": "Angular frontend for the repo health project.", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "./node_modules/karma/bin/karma start" }, "author": "", "license": "MIT", "dependencies": { "angular": "^1.6.2", "angular-ui-router": "^0.4.2" + }, + "devDependencies": { + "angular-mocks": "^1.6.2", + "jasmine-core": "^2.5.2", + "karma": "^1.4.1", + "karma-chrome-launcher": "^2.0.0", + "karma-jasmine": "^1.1.0" } } diff --git a/repo_health/index/static/src/components/search/search.spec.js b/repo_health/index/static/src/components/search/search.spec.js new file mode 100644 index 0000000..e6180f9 --- /dev/null +++ b/repo_health/index/static/src/components/search/search.spec.js @@ -0,0 +1,25 @@ +describe('Search', () => { + beforeEach(module('components.search')); + + describe('SearchController', () => { + let $componentController; + let controller; + + beforeEach(inject(($injector) => { + $componentController = $injector.get('$componentController'); + controller = $componentController('search'); + })); + + describe('constructor', () => { + it('should setup the controller', () => { + expect(controller).toBeDefined; + }); + }); + + describe('getStats', () => { + it('should return the stats', () => { + //Add tests when function is implemented + }); + }); + }); +}); \ No newline at end of file From 8ceb4f8061bdb78312df4b5ca3c19318bcdd7d6e Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Mon, 13 Feb 2017 18:32:15 -0600 Subject: [PATCH 07/99] Added license identifiers to ui files --- repo_health/index/static/assets/css/styles.css | 12 ++++++++++++ repo_health/index/static/src/app.js | 13 +++++++++++++ .../src/components/search/search.component.js | 12 ++++++++++++ .../src/components/search/search.controller.js | 13 +++++++++++++ .../static/src/components/search/search.module.js | 12 ++++++++++++ 5 files changed, 62 insertions(+) diff --git a/repo_health/index/static/assets/css/styles.css b/repo_health/index/static/assets/css/styles.css index a71dd43..38d967e 100644 --- a/repo_health/index/static/assets/css/styles.css +++ b/repo_health/index/static/assets/css/styles.css @@ -1,3 +1,15 @@ +/* +* styles.css - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This file holds the general css for the application +*/ + .search-repo { width: 75%; height: 200px; diff --git a/repo_health/index/static/src/app.js b/repo_health/index/static/src/app.js index 61c9b9e..57a3034 100644 --- a/repo_health/index/static/src/app.js +++ b/repo_health/index/static/src/app.js @@ -1,3 +1,16 @@ +/* +* app.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is where the angular app gets bootstraped. +* It will set up all the global configuration. +*/ + (function () { angular.module('repo-health', [ 'components' diff --git a/repo_health/index/static/src/components/search/search.component.js b/repo_health/index/static/src/components/search/search.component.js index e87cfa0..541242a 100644 --- a/repo_health/index/static/src/components/search/search.component.js +++ b/repo_health/index/static/src/components/search/search.component.js @@ -1,3 +1,15 @@ +/* +* search.component.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the creation of the search component. +*/ + (function () { var search = { templateUrl: '/static/src/components/search/search.html', diff --git a/repo_health/index/static/src/components/search/search.controller.js b/repo_health/index/static/src/components/search/search.controller.js index 4bc89f4..22c1dde 100644 --- a/repo_health/index/static/src/components/search/search.controller.js +++ b/repo_health/index/static/src/components/search/search.controller.js @@ -1,3 +1,16 @@ +/* +* search.controller.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the controller that will be used in the search component. +* It will allow a user to search on a repo +*/ + (function () { angular.module('components.search') .controller('SearchController', SearchController); diff --git a/repo_health/index/static/src/components/search/search.module.js b/repo_health/index/static/src/components/search/search.module.js index ce7dd67..a7aad6c 100644 --- a/repo_health/index/static/src/components/search/search.module.js +++ b/repo_health/index/static/src/components/search/search.module.js @@ -1,3 +1,15 @@ +/* +* search.module.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the module definition for the search component +*/ + (function () { angular.module('components.search', [ 'ui.router' From 9d44f862266d5c7d3a1dee586db985fbb168dc16 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Mon, 13 Feb 2017 21:26:28 -0600 Subject: [PATCH 08/99] Added to components.module.js --- .../index/static/src/components/components.module.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/repo_health/index/static/src/components/components.module.js b/repo_health/index/static/src/components/components.module.js index 7d5b9fa..aaad30d 100644 --- a/repo_health/index/static/src/components/components.module.js +++ b/repo_health/index/static/src/components/components.module.js @@ -1,3 +1,15 @@ +/* +* component.module.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the definitions for all of the components used in this application. +*/ + (function () { angular.module('components', [ 'components.search' From ceccfa13c41b21149c931c9607d16e5e4faa98bc Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Mon, 13 Feb 2017 21:42:49 -0600 Subject: [PATCH 09/99] Added license to test files --- .../static/src/components/search/search.spec.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/repo_health/index/static/src/components/search/search.spec.js b/repo_health/index/static/src/components/search/search.spec.js index e6180f9..1ce7ec0 100644 --- a/repo_health/index/static/src/components/search/search.spec.js +++ b/repo_health/index/static/src/components/search/search.spec.js @@ -1,3 +1,15 @@ +/* +* search.spec.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the test file for the search component +*/ + describe('Search', () => { beforeEach(module('components.search')); From 512a62fbef6a413238044d3fde9dc0b5567e5a9d Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 13 Feb 2017 21:48:38 -0600 Subject: [PATCH 10/99] Update reademe. --- README.md | 4 ++++ docs/rest_api/Repos.md | 2 +- repo_health/index/templates/index.html | 5 ++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b1ae5d7..388181a 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,10 @@ Assumptions made about production: - Apache httpd server is used to serve app using mod_wsgi. - All static files are served from Apache using a redirect from url `/static/` to a static documents folder. This folder is created using `python manage.py collectstatic`. This is not necessary in development. +##License and Copyright +All source code is covered by th MIT license. This license is located in the LICENSE.txt file at the root of the project. + +All other material, such as documentation, is covered by the Creative Commons - Attribution, or the CC B,Y license. ##Contributing External contributions are not being accepted at this time. For existing contributors, please use the following header documentation at the top of each file: diff --git a/docs/rest_api/Repos.md b/docs/rest_api/Repos.md index 4fd1063..c17bc1e 100644 --- a/docs/rest_api/Repos.md +++ b/docs/rest_api/Repos.md @@ -26,6 +26,6 @@ URL: "labels_count": int, "commits_count": int, "milestones_count": int, - "latest_commit": date str + "pull_requests_count": int } ``` \ No newline at end of file diff --git a/repo_health/index/templates/index.html b/repo_health/index/templates/index.html index 10d49aa..07abac5 100644 --- a/repo_health/index/templates/index.html +++ b/repo_health/index/templates/index.html @@ -33,6 +33,5 @@

Repo Health Assessment

- - - \ No newline at end of file + + From 4fd141c5ca5a1ff99f1fa59ac71e36f864e219f1 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Tue, 14 Feb 2017 21:35:27 -0600 Subject: [PATCH 11/99] Updated the migrations and added serializers package. --- README.md | 2 +- docs/rest_api/Repos.md | 7 +- .../gh_commits/migrations/0001_initial.py | 6 +- .../gh_issues/migrations/0001_initial.py | 13 ++- .../gh_projects/migrations/0001_initial.py | 23 +++--- repo_health/gh_projects/models/GhFork.py | 2 +- repo_health/gh_projects/models/GhProject.py | 10 +++ repo_health/gh_projects/models/GhRepoLabel.py | 3 +- .../gh_projects/models/GhRepoMilestone.py | 5 +- .../serializers/GhProjectSerializer.py | 82 +++++++++++++++++++ .../gh_projects/serializers/__init__.py | 13 +++ repo_health/gh_projects/tests.py | 8 +- repo_health/gh_projects/views.py | 47 +---------- .../migrations/0001_initial.py | 8 +- .../gh_users/migrations/0001_initial.py | 12 +-- repo_health/gh_users/models/GhUser.py | 7 ++ repo_health/gh_users/models/__init__.py | 10 ++- repo_health/gh_users/tests.py | 9 ++ 18 files changed, 180 insertions(+), 87 deletions(-) create mode 100644 repo_health/gh_projects/serializers/GhProjectSerializer.py create mode 100644 repo_health/gh_projects/serializers/__init__.py diff --git a/README.md b/README.md index 388181a..ec63761 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Repository Health Project for CSCI 4900 -The repository hold the proof of concept for the repository health and sustainability project for CSCI 4900 at the Univeristy of Nebraska at Omaha. This repository will hold the backend and frontend source code to extract data from Github and ghtorrent and prodvide statistics about a selected repository. Description of the backend and frontend source are provided. +This repository holds the proof of concept for the repository health and sustainability project for CSCI 4900 at the Univeristy of Nebraska at Omaha. This repository will hold the backend and frontend source code to extract data from Github and ghtorrent and prodvide statistics about a selected repository. Description of the backend and frontend source are provided. ## Backend The Django web framework is used in the project to leverage quick development and the third party packages available. Python requirements are kept in the requirements.txt file, and this file is generated using `pip freeze > requirements.txt`. diff --git a/docs/rest_api/Repos.md b/docs/rest_api/Repos.md index c17bc1e..c75d986 100644 --- a/docs/rest_api/Repos.md +++ b/docs/rest_api/Repos.md @@ -21,11 +21,14 @@ URL: "forked_from": null or int, "contribs_count": int, "watchers_count": int, - "watch_not_contribs_counts: int, + "maintainers_count": int, + "watch_not_contribs_counts": int, "orgs_of_contribs_count": int, "labels_count": int, "commits_count": int, "milestones_count": int, - "pull_requests_count": int + "pull_requests_count": int, + "owned_by_org": bool, + "forks_count": int } ``` \ No newline at end of file diff --git a/repo_health/gh_commits/migrations/0001_initial.py b/repo_health/gh_commits/migrations/0001_initial.py index bce69eb..9f1e771 100644 --- a/repo_health/gh_commits/migrations/0001_initial.py +++ b/repo_health/gh_commits/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.5 on 2017-02-04 19:51 +# Generated by Django 1.10.5 on 2017-02-15 03:15 from __future__ import unicode_literals from django.db import migrations, models @@ -23,8 +23,8 @@ class Migration(migrations.Migration): ], options={ 'managed': False, - 'verbose_name': 'GitHub Commit', 'db_table': 'commits', + 'verbose_name': 'GitHub Commit', }, ), migrations.CreateModel( @@ -40,8 +40,8 @@ class Migration(migrations.Migration): ], options={ 'managed': False, - 'verbose_name': 'GitHub Commit Comment', 'db_table': 'commit_comments', + 'verbose_name': 'GitHub Commit Comment', }, ), migrations.CreateModel( diff --git a/repo_health/gh_issues/migrations/0001_initial.py b/repo_health/gh_issues/migrations/0001_initial.py index 80006f7..675c9f1 100644 --- a/repo_health/gh_issues/migrations/0001_initial.py +++ b/repo_health/gh_issues/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.5 on 2017-02-04 19:51 +# Generated by Django 1.10.5 on 2017-02-15 03:16 from __future__ import unicode_literals from django.db import migrations, models @@ -23,23 +23,22 @@ class Migration(migrations.Migration): ('ext_ref_id', models.CharField(max_length=24)), ], options={ - 'managed': False, 'verbose_name': 'GitHub Issue', 'db_table': 'issues', + 'managed': False, }, ), migrations.CreateModel( name='GhIssueComment', fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('comment_id', models.TextField()), + ('comment_id', models.TextField(primary_key=True, serialize=False)), ('created_at', models.DateTimeField()), ('ext_ref_id', models.CharField(max_length=24)), ], options={ - 'managed': False, 'verbose_name': 'GitHub Issue Comment', 'db_table': 'issue_comments', + 'managed': False, }, ), migrations.CreateModel( @@ -53,9 +52,9 @@ class Migration(migrations.Migration): ('ext_ref_id', models.CharField(max_length=24)), ], options={ - 'managed': False, 'verbose_name': 'GitHub Issue Event', 'db_table': 'issue_events', + 'managed': False, }, ), migrations.CreateModel( @@ -64,8 +63,8 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], options={ - 'managed': False, 'db_table': 'issue_labels', + 'managed': False, }, ), ] diff --git a/repo_health/gh_projects/migrations/0001_initial.py b/repo_health/gh_projects/migrations/0001_initial.py index 486f064..133ebd3 100644 --- a/repo_health/gh_projects/migrations/0001_initial.py +++ b/repo_health/gh_projects/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.5 on 2017-02-04 19:51 +# Generated by Django 1.10.5 on 2017-02-15 03:16 from __future__ import unicode_literals from django.db import migrations, models @@ -16,15 +16,14 @@ class Migration(migrations.Migration): migrations.CreateModel( name='GhFork', fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('fork_id', models.IntegerField(unique=True)), + ('fork_id', models.IntegerField(primary_key=True, serialize=False, unique=True)), ('created_at', models.DateTimeField()), ('ext_ref_id', models.CharField(max_length=24)), ], options={ - 'verbose_name': 'GitHub Fork', - 'managed': False, 'db_table': 'forks', + 'managed': False, + 'verbose_name': 'GitHub Fork', }, ), migrations.CreateModel( @@ -40,9 +39,9 @@ class Migration(migrations.Migration): ('deleted', models.IntegerField()), ], options={ - 'verbose_name': 'GitHub Project', - 'managed': False, 'db_table': 'projects', + 'managed': False, + 'verbose_name': 'GitHub Project', }, ), migrations.CreateModel( @@ -51,8 +50,8 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], options={ - 'managed': False, 'db_table': 'project_commits', + 'managed': False, }, ), migrations.CreateModel( @@ -63,9 +62,9 @@ class Migration(migrations.Migration): ('ext_ref_id', models.CharField(max_length=24)), ], options={ - 'verbose_name': 'GitHub Repo Label', - 'managed': False, 'db_table': 'repo_labels', + 'managed': False, + 'verbose_name': 'GitHub Repo Label', }, ), migrations.CreateModel( @@ -76,9 +75,9 @@ class Migration(migrations.Migration): ('ext_ref_id', models.CharField(max_length=24)), ], options={ - 'verbose_name': 'GitHub Repo Milestone', - 'managed': False, 'db_table': 'repo_milestones', + 'managed': False, + 'verbose_name': 'GitHub Repo Milestone', }, ), ] diff --git a/repo_health/gh_projects/models/GhFork.py b/repo_health/gh_projects/models/GhFork.py index bddcd6c..b952a50 100644 --- a/repo_health/gh_projects/models/GhFork.py +++ b/repo_health/gh_projects/models/GhFork.py @@ -22,7 +22,7 @@ class GhFork(models.Model): forked_from = models.ForeignKey( 'gh_projects.GhProject', models.DO_NOTHING, ) - fork_id = models.IntegerField(unique=True) + fork_id = models.IntegerField(unique=True, primary_key=True) created_at = models.DateTimeField() ext_ref_id = models.CharField(max_length=24) diff --git a/repo_health/gh_projects/models/GhProject.py b/repo_health/gh_projects/models/GhProject.py index fda3884..57031e8 100644 --- a/repo_health/gh_projects/models/GhProject.py +++ b/repo_health/gh_projects/models/GhProject.py @@ -17,6 +17,7 @@ class GhProject(m.Model): + url = m.CharField(max_length=255, blank=True, null=True) owner = m.ForeignKey('gh_users.GhUser', m.DO_NOTHING, blank=True, null=True) name = m.CharField(max_length=255) @@ -46,9 +47,18 @@ class GhProject(m.Model): related_name='watched_repos' ) + forks = m.ManyToManyField( + 'gh_projects.GhProject', + through='gh_projects.GhFork', + related_name='parents' + ) + def __str__(self): return self.name + def is_owned_by_org(self): + return self.owner.is_org() + class Meta: managed = False db_table = 'projects' diff --git a/repo_health/gh_projects/models/GhRepoLabel.py b/repo_health/gh_projects/models/GhRepoLabel.py index 7ec484c..b88fb3c 100644 --- a/repo_health/gh_projects/models/GhRepoLabel.py +++ b/repo_health/gh_projects/models/GhRepoLabel.py @@ -14,7 +14,8 @@ class GhRepoLabel(models.Model): repo = models.ForeignKey( - 'gh_projects.GhProject', models.DO_NOTHING, blank=True, null=True + 'gh_projects.GhProject', models.DO_NOTHING, blank=True, null=True, + related_name='labels' ) name = models.CharField(max_length=24) ext_ref_id = models.CharField(max_length=24) diff --git a/repo_health/gh_projects/models/GhRepoMilestone.py b/repo_health/gh_projects/models/GhRepoMilestone.py index 5804d91..5f9aa73 100644 --- a/repo_health/gh_projects/models/GhRepoMilestone.py +++ b/repo_health/gh_projects/models/GhRepoMilestone.py @@ -13,7 +13,10 @@ from django.db import models class GhRepoMilestone(models.Model): - repo = models.ForeignKey('gh_projects.GhProject', models.DO_NOTHING, blank=True, null=True) + repo = models.ForeignKey('gh_projects.GhProject', models.DO_NOTHING, + blank=True, null=True, + related_name='milestones' + ) name = models.CharField(max_length=24) ext_ref_id = models.CharField(max_length=24) diff --git a/repo_health/gh_projects/serializers/GhProjectSerializer.py b/repo_health/gh_projects/serializers/GhProjectSerializer.py new file mode 100644 index 0000000..5ef30d5 --- /dev/null +++ b/repo_health/gh_projects/serializers/GhProjectSerializer.py @@ -0,0 +1,82 @@ +""" +serializers.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Serializer for a GitHub repo. +""" + +from rest_framework.serializers import ModelSerializer, SerializerMethodField +from repo_health.gh_users.models import GhUser +from ..models import GhProject + +class GhProjectSerializer(ModelSerializer): + _contribs_count = None + _watch_not_contribs_count = None + _orgs_of_contribs_count = None + _labels_count = None + _commits_count = None + _latest_commit = None + + contribs_count = SerializerMethodField() + watchers_count = SerializerMethodField() + commits_count = SerializerMethodField() + milestones_count = SerializerMethodField() + latest_commit_created_at = SerializerMethodField() + labels_count = SerializerMethodField() + orgs_of_contribs_count = SerializerMethodField() + owned_by_org = SerializerMethodField() + forks_count = SerializerMethodField() + + def __init__(self, *args, **kwargs): + """ + Get some statistics for repo. + """ + super().__init__(*args, **kwargs) + repo = args[0].first() + if repo is not None: + commits = (repo.commits_m2m.all() | repo.commits_fk.all()).order_by('-created_at') + commit_users = GhUser.objects.filter(commits__in=commits).distinct() + self._commits_count = commits.count() + self._contribs_count = commit_users.count() + self._latest_commit = commits.first().created_at + self._orgs_of_contribs_count = GhUser.objects.filter(members__in=commit_users).exclude(id=repo.owner.id).count() + + + def get_orgs_of_contribs_count(self, repo): + return self._orgs_of_contribs_count + + def get_contribs_count(self, obj): + return self._contribs_count + + def get_commits_count(self, obj): + return self._commits_count + + def get_maintainers_count(self, repo): + return repo.maintainers.count() + + def get_watchers_count(self, repo): + return repo.watchers.count() + + def get_milestones_count(self, repo): + return repo.milestones.count() + + def get_latest_commit_created_at(self, repo): + return self._latest_commit + + def get_labels_count(self, repo): + return repo.labels.count() + + def get_owned_by_org(self, repo): + return repo.is_owned_by_org() + + def get_forks_count(self, repo): + return repo.forks.all().count() + + class Meta: + model = GhProject + exclude = ['commits_m2m', 'maintainers', 'watchers', 'url', 'forks',] \ No newline at end of file diff --git a/repo_health/gh_projects/serializers/__init__.py b/repo_health/gh_projects/serializers/__init__.py new file mode 100644 index 0000000..fd324d0 --- /dev/null +++ b/repo_health/gh_projects/serializers/__init__.py @@ -0,0 +1,13 @@ +""" +__init__.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Import all classes from package. +""" + +from .GhProjectSerializer import GhProjectSerializer diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 5007df8..70b45b7 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -7,8 +7,7 @@ Author(s) of this file: J. Harding -Test the generated models are functioning as expected. -Specifically test database relationships to show no error thrown and a result is returned. +Test projects """ @@ -20,6 +19,11 @@ class TestGhProject(TestCase): + """ + Test the generated models are functioning as expected. + Specifically test database relationships to show no error thrown and a result is returned. + """ + project = None client = None diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index 508fe15..a417025 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -12,58 +12,13 @@ from rest_framework.mixins import ListModelMixin from rest_framework.viewsets import GenericViewSet -from rest_framework.serializers import ModelSerializer, SerializerMethodField from rest_framework.exceptions import NotFound from rest_framework.status import HTTP_404_NOT_FOUND from repo_health.gh_users.models import GhUser from .models import GhProject +from .serializers import GhProjectSerializer - -class GhProjectSerializer(ModelSerializer): - _contribs_count = None - _watchers_count = None - _watch_not_contribs_count = None - _orgs_of_contribs_count = None - _labels_count = None - _commits_count = None - _milestones_count = None - _latest_commit = None - - contribs_count = SerializerMethodField() - watchers_count = SerializerMethodField() - # watch_not_contribs_count = SerializerMethodField() - # commits_count = SerializerMethodField() - # milestones_count = SerializerMethodField() - # labels_count = SerializerMethodField() - # orgs_of_contribs_count = SerializerMethodField() - # commits_count = SerializerMethodField() - - - def __init__(self, *args, **kwargs): - """ - Get some statistics for repo. - """ - super().__init__(*args, **kwargs) - repo = args[0].first() - if repo is not None: - commits = repo.commits_m2m.all() | repo.commits_fk.all() - self._commits_count = commits.count() - self._contribs_count = GhUser.objects.filter(commits__in=commits).distinct().count() - # print (dir(repo)) - self._watchers_count = repo.ghwatcher_set.count() - - def get_watchers_count(self, obj): - return self._watchers_count - - def get_contribs_count(self, obj): - return self._contribs_count - - class Meta: - model = GhProject - exclude = ['commits_m2m', 'maintainers', 'watchers', 'url',] - - class GhProjectViewSet(ListModelMixin, GenericViewSet): queryset = GhProject.objects.all() serializer_class = GhProjectSerializer diff --git a/repo_health/gh_pull_requests/migrations/0001_initial.py b/repo_health/gh_pull_requests/migrations/0001_initial.py index 0d66aa4..95d316c 100644 --- a/repo_health/gh_pull_requests/migrations/0001_initial.py +++ b/repo_health/gh_pull_requests/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.5 on 2017-02-04 19:51 +# Generated by Django 1.10.5 on 2017-02-15 03:16 from __future__ import unicode_literals from django.db import migrations, models @@ -22,8 +22,8 @@ class Migration(migrations.Migration): ('merged', models.IntegerField()), ], options={ - 'managed': False, 'verbose_name': 'GitHub Pull Request', + 'managed': False, 'db_table': 'pull_requests', }, ), @@ -37,9 +37,9 @@ class Migration(migrations.Migration): ('ext_ref_id', models.CharField(max_length=24, primary_key=True, serialize=False)), ], options={ - 'managed': False, 'verbose_name': 'GitHub Pull Request Comment', 'db_table': 'pull_request_comments', + 'managed': False, }, ), migrations.CreateModel( @@ -61,9 +61,9 @@ class Migration(migrations.Migration): ('action', models.CharField(max_length=255)), ], options={ - 'managed': False, 'verbose_name': 'GitHub Pull Request History', 'db_table': 'pull_request_history', + 'managed': False, }, ), ] diff --git a/repo_health/gh_users/migrations/0001_initial.py b/repo_health/gh_users/migrations/0001_initial.py index 20d9a25..ea8780a 100644 --- a/repo_health/gh_users/migrations/0001_initial.py +++ b/repo_health/gh_users/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.5 on 2017-02-04 19:51 +# Generated by Django 1.10.5 on 2017-02-15 03:16 from __future__ import unicode_literals from django.db import migrations, models @@ -20,8 +20,8 @@ class Migration(migrations.Migration): ('ext_ref_id', models.CharField(max_length=24, primary_key=True, serialize=False)), ], options={ - 'db_table': 'followers', 'verbose_name': 'GitHub Follower', + 'db_table': 'followers', 'managed': False, }, ), @@ -32,8 +32,8 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField()), ], options={ - 'db_table': 'organization_members', 'verbose_name': 'GitHub Organization Member', + 'db_table': 'organization_members', 'managed': False, }, ), @@ -44,8 +44,8 @@ class Migration(migrations.Migration): ('ext_ref_id', models.CharField(max_length=24, primary_key=True, serialize=False)), ], options={ - 'db_table': 'project_members', 'verbose_name': 'GitHub Project Member', + 'db_table': 'project_members', 'managed': False, }, ), @@ -63,8 +63,8 @@ class Migration(migrations.Migration): ('type', models.CharField(max_length=255)), ], options={ - 'db_table': 'users', 'verbose_name': 'GitHub User', + 'db_table': 'users', 'managed': False, }, ), @@ -75,8 +75,8 @@ class Migration(migrations.Migration): ('ext_ref_id', models.CharField(max_length=24, primary_key=True, serialize=False)), ], options={ - 'db_table': 'watchers', 'verbose_name': 'GitHub Watcher', + 'db_table': 'watchers', 'managed': False, }, ), diff --git a/repo_health/gh_users/models/GhUser.py b/repo_health/gh_users/models/GhUser.py index 55f7a99..024ebdd 100644 --- a/repo_health/gh_users/models/GhUser.py +++ b/repo_health/gh_users/models/GhUser.py @@ -2,6 +2,10 @@ class GhUser(m.Model): + + ORG_TYPE = 'ORG' + USER_TYPE = 'USR' + login = m.CharField(unique=True, max_length=255) name = m.CharField(max_length=255, blank=True, null=True) company = m.CharField(max_length=255, blank=True, null=True) @@ -22,6 +26,9 @@ class GhUser(m.Model): through='gh_users.GhOrgMember' ) + def is_org(self): + return self.type == self.ORG_TYPE + class Meta: managed = False db_table = 'users' diff --git a/repo_health/gh_users/models/__init__.py b/repo_health/gh_users/models/__init__.py index 628338c..c8a4b69 100644 --- a/repo_health/gh_users/models/__init__.py +++ b/repo_health/gh_users/models/__init__.py @@ -1,5 +1,13 @@ """ -Import all models package here. +__init__.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Import all models from package. """ from .GhUser import GhUser diff --git a/repo_health/gh_users/tests.py b/repo_health/gh_users/tests.py index bbf8bb4..3e65002 100644 --- a/repo_health/gh_users/tests.py +++ b/repo_health/gh_users/tests.py @@ -31,7 +31,16 @@ def setUp(self): self.maintain_user = GhUser.objects.filter( maintain_repos__isnull = False ).first() + + self.organization = GhUser.objects.filter( + type=GhUser.ORG_TYPE + ).first() + + def test_org_is_org(self): + self.assertTrue(self.organization.is_org()) + def test_user_is_not_org(self): + self.assertFalse(self.maintain_user.is_org()) def test_get_m2m(self): self.assertTrue(self.orgs_user.organizations.all()) From 49dbf7119e24ca634742daceffd93666e6c805ff Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Tue, 14 Feb 2017 22:22:53 -0600 Subject: [PATCH 12/99] Updated docs. Added some metrics to pull requests. --- docs/metrics/PullRequests.md | 4 ++++ docs/metrics/Repos.md | 4 ++-- docs/rest_api/PullRequests.md | 21 +++++++++++++++++++++ docs/rest_api/Repos.md | 3 +-- 4 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 docs/rest_api/PullRequests.md diff --git a/docs/metrics/PullRequests.md b/docs/metrics/PullRequests.md index 5717b62..9b1747c 100644 --- a/docs/metrics/PullRequests.md +++ b/docs/metrics/PullRequests.md @@ -14,4 +14,8 @@ - total number of comments on prs - total number of comments from maintainers - most contributing user (user with most accepted prs) + - avg size of pr? + - not maintainer pr past year? + - not orn member pr? past year? + - avg comments per pr diff --git a/docs/metrics/Repos.md b/docs/metrics/Repos.md index d349207..3e39b93 100644 --- a/docs/metrics/Repos.md +++ b/docs/metrics/Repos.md @@ -2,7 +2,7 @@ msr14 limitations - has no recognition of releases, tags, stars, downloads - - has an empty table: RepoMilestone + - has empty tables: GhRepoMilestone, GhFork ###From slides @@ -20,7 +20,7 @@ msr14 limitations - numbers of watchers - number of watchers who aren't contributors - organizations of contributors - - project doesn't have an organization directly + - number of forks - number of labels - is a fork - number of commits diff --git a/docs/rest_api/PullRequests.md b/docs/rest_api/PullRequests.md new file mode 100644 index 0000000..0a298fd --- /dev/null +++ b/docs/rest_api/PullRequests.md @@ -0,0 +1,21 @@ +#Pull requests stats for a repo + +Pull request stats are retrieved with the repo id. `prs` is used as an abbreviation for pull requests. +A GET request is made to: +- `/api/v1/gh-projects//pull-requests` +- Note the repo id embedded in the URL + +``` +{ + "prs_count": int, + "prs_last_year: 12 element array, + "latest_pr_created_at": datetime str, + "contrib_most_prs": str - login, + "prs_no_maintainer_comments": int, + "prs_no_comments": int, + "avg_lifetime": str, + "not_maintainer_prs": int, + "avg_comment_per_pr": float, + "prs_from_outside_org": int +} +``` \ No newline at end of file diff --git a/docs/rest_api/Repos.md b/docs/rest_api/Repos.md index c75d986..e780b7a 100644 --- a/docs/rest_api/Repos.md +++ b/docs/rest_api/Repos.md @@ -22,12 +22,11 @@ URL: "contribs_count": int, "watchers_count": int, "maintainers_count": int, - "watch_not_contribs_counts": int, + "milestones_count": int, "orgs_of_contribs_count": int, "labels_count": int, "commits_count": int, "milestones_count": int, - "pull_requests_count": int, "owned_by_org": bool, "forks_count": int } From 9c920f4014f3512f488a54a7652312dc77d144fe Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 15 Feb 2017 14:16:58 -0600 Subject: [PATCH 13/99] Added Milestone1.md --- docs/Milestone1.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 docs/Milestone1.md diff --git a/docs/Milestone1.md b/docs/Milestone1.md new file mode 100644 index 0000000..a1eddb1 --- /dev/null +++ b/docs/Milestone1.md @@ -0,0 +1,43 @@ +#Milestone 1 + +##System Description +The information system being built provides an unbiased evaluation of a GitHub repository using data collected by the GHTorrent project. The system is a web based interface and retrieves data about a GitHub repository using a URL specified by the user. The intent is to provide the user with usable information about a GitHub repository so the user can make an informed decision about the health and sustainability of the repository and the community supporting it. The system is not meant to provide any value to the statistics. + +The system has many parts. The backend server serves data to the web client using a REST API in the JSON format. The web client uses the JSON data to render the visualization of the data. + +The current state of the system is in a proof of concept and not ready for a production environment. The proof of concept supplies basic statistics about a repository and leaves out complex manipulation. + +##Development Environment +Our development environment consists of several different tools. Our development operating system is a Linux/Unix (Mac) environment. Our database management system is MySQL. Our server is running on Python 3.5+ and is using the Django web framework and dev server. We is using Python’s `virtualenv` to keep every developers python environment the same. Our front end is using the node package manager (npm) to manage and keep our dependencies in sync. + + +##Data Flow Diagram +Our Data Flow Diagram can be found [here](https://github.com/jakeharding/repo-health/blob/master/docs/Data%20Flow%20Diagram.pdf). + +##Database Schema +We are using ghtorrent's schema. It can be found [here](http://ghtorrent.org/files/schema.pdf). + +##Copyright and License +Licenses used for this project cover two areas: documentation and software. The software is covered under the MIT license and the documentation is covered under CC BY. + +Each file has the following documentation: + +``` +fileName.ext - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + Your name or github username + +Brief description of the file. +``` + +##Contributions +#####Jake: +- Backend implementation +- Documentation +####Benji: +- Frontend implementation +- Documentation From cb546766626de0adbbddad6984a1c2801ca99751 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 15 Feb 2017 14:20:46 -0600 Subject: [PATCH 14/99] Fixed formatting --- docs/Milestone1.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Milestone1.md b/docs/Milestone1.md index a1eddb1..4ac22a8 100644 --- a/docs/Milestone1.md +++ b/docs/Milestone1.md @@ -38,6 +38,7 @@ Brief description of the file. #####Jake: - Backend implementation - Documentation + ####Benji: - Frontend implementation - Documentation From e2980b7d35f4ca3129fdacf8852a53841cfcb687 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 15 Feb 2017 14:28:17 -0600 Subject: [PATCH 15/99] Contribution updates --- docs/Milestone1.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/Milestone1.md b/docs/Milestone1.md index 4ac22a8..4e4552e 100644 --- a/docs/Milestone1.md +++ b/docs/Milestone1.md @@ -36,9 +36,7 @@ Brief description of the file. ##Contributions #####Jake: -- Backend implementation -- Documentation +Jake is responsible for implementation of connecting to the database, the web server for the REST API, and all related documentation. ####Benji: -- Frontend implementation -- Documentation +Benji is responsible for the frontend implementation. This includes UI/UX Design and the display of information from the server on the UI. All documentation for the frontend will be written by Benji. From d97be8897b46fd3cf0746147de2606a7e17fd116 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 15 Feb 2017 14:38:03 -0600 Subject: [PATCH 16/99] Update milestone1. --- README.md | 2 +- docs/Milestone1.md | 28 +++++++++++++++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 416b2e9..6a85fdb 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Assumptions made about production: - All static files are served from Apache using a redirect from url `/static/` to a static documents folder. This folder is created using `python manage.py collectstatic`. This is not necessary in development. ##License and Copyright -All source code is covered by th MIT license. This license is located in the LICENSE.txt file at the root of the project. +All source code is covered by the MIT license. This license is located in the LICENSE.txt file at the root of the project. All other material, such as documentation, is covered by the Creative Commons - Attribution, or the CC B,Y license. diff --git a/docs/Milestone1.md b/docs/Milestone1.md index 4e4552e..38f3ea6 100644 --- a/docs/Milestone1.md +++ b/docs/Milestone1.md @@ -1,23 +1,25 @@ -#Milestone 1 +# Milestone 1 -##System Description -The information system being built provides an unbiased evaluation of a GitHub repository using data collected by the GHTorrent project. The system is a web based interface and retrieves data about a GitHub repository using a URL specified by the user. The intent is to provide the user with usable information about a GitHub repository so the user can make an informed decision about the health and sustainability of the repository and the community supporting it. The system is not meant to provide any value to the statistics. +## System Description +The information system being built provides an unbiased evaluation of a GitHub repository using data collected by the GHTorrent project. The system is a web based interface and retrieves data about a GitHub repository using a URL specified by the user. The source code for the system is hosted on GitHub at: https://github.com/jakeharding/repo-health. -The system has many parts. The backend server serves data to the web client using a REST API in the JSON format. The web client uses the JSON data to render the visualization of the data. +The intent is to provide the user with usable information about a GitHub repository so the user can make an informed decision about the health and sustainability of the repository and the community supporting it. The system is not meant to provide any value to the statistics. -The current state of the system is in a proof of concept and not ready for a production environment. The proof of concept supplies basic statistics about a repository and leaves out complex manipulation. +The system has many parts. The backend provides a connection to the database, serialization of the data, and serving the data to the client in JSON format. The web client uses the JSON data to render the visualization of the data. Both parts are included in the source code repository for convenience, but the system is built so the separation of the frontend and backend can be easily achieved. -##Development Environment -Our development environment consists of several different tools. Our development operating system is a Linux/Unix (Mac) environment. Our database management system is MySQL. Our server is running on Python 3.5+ and is using the Django web framework and dev server. We is using Python’s `virtualenv` to keep every developers python environment the same. Our front end is using the node package manager (npm) to manage and keep our dependencies in sync. +The current state of the system is in a proof of concept and is not ready for a production environment. The proof of concept supplies basic statistics about a repository and leaves out complex data manipulation. +## Development Environment +Our development environment consists of several different tools. Our development operating system is a Linux/Unix (Mac) environment. Our database management system is MySQL. Our server is running on Python 3.5+ and is using the Django web framework and dev server. Python’s `virtualenv` is used to keep every developers python environment the same. Our front end is using the node package manager (npm) to manage and keep our dependencies in sync. -##Data Flow Diagram + +## Data Flow Diagram Our Data Flow Diagram can be found [here](https://github.com/jakeharding/repo-health/blob/master/docs/Data%20Flow%20Diagram.pdf). -##Database Schema +## Database Schema We are using ghtorrent's schema. It can be found [here](http://ghtorrent.org/files/schema.pdf). -##Copyright and License +## Copyright and License Licenses used for this project cover two areas: documentation and software. The software is covered under the MIT license and the documentation is covered under CC BY. Each file has the following documentation: @@ -34,9 +36,9 @@ Author(s) of this file: Brief description of the file. ``` -##Contributions -#####Jake: +## Contributions +##### Jake: Jake is responsible for implementation of connecting to the database, the web server for the REST API, and all related documentation. -####Benji: +#### Benji: Benji is responsible for the frontend implementation. This includes UI/UX Design and the display of information from the server on the UI. All documentation for the frontend will be written by Benji. From b4ad1e213c997db30a0055fb33924ec8112cc1b3 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Thu, 16 Feb 2017 09:33:53 -0600 Subject: [PATCH 17/99] Formatting fix Fix to a very minor formatting thing. --- docs/Milestone1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Milestone1.md b/docs/Milestone1.md index 38f3ea6..485ba34 100644 --- a/docs/Milestone1.md +++ b/docs/Milestone1.md @@ -40,5 +40,5 @@ Brief description of the file. ##### Jake: Jake is responsible for implementation of connecting to the database, the web server for the REST API, and all related documentation. -#### Benji: +##### Benji: Benji is responsible for the frontend implementation. This includes UI/UX Design and the display of information from the server on the UI. All documentation for the frontend will be written by Benji. From ff35994dcdb126aac23072cc5eb839d30ebeeb4c Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 22 Feb 2017 14:17:22 -0600 Subject: [PATCH 18/99] Added dependencies and initial webpack config --- .../static/{ => client}/assets/css/styles.css | 0 .../assets/vendor/bootstrap.min.css | 0 .../index/static/{ => client}/src/app.js | 0 .../src/components/components.module.js | 0 .../src/components/search/search.component.js | 0 .../components/search/search.controller.js | 0 .../src/components/search/search.html | 0 .../src/components/search/search.module.js | 0 .../src/components/search/search.spec.js | 0 repo_health/index/static/package.json | 22 +++- repo_health/index/static/webpack.config.js | 101 ++++++++++++++++++ 11 files changed, 122 insertions(+), 1 deletion(-) rename repo_health/index/static/{ => client}/assets/css/styles.css (100%) rename repo_health/index/static/{ => client}/assets/vendor/bootstrap.min.css (100%) rename repo_health/index/static/{ => client}/src/app.js (100%) rename repo_health/index/static/{ => client}/src/components/components.module.js (100%) rename repo_health/index/static/{ => client}/src/components/search/search.component.js (100%) rename repo_health/index/static/{ => client}/src/components/search/search.controller.js (100%) rename repo_health/index/static/{ => client}/src/components/search/search.html (100%) rename repo_health/index/static/{ => client}/src/components/search/search.module.js (100%) rename repo_health/index/static/{ => client}/src/components/search/search.spec.js (100%) create mode 100644 repo_health/index/static/webpack.config.js diff --git a/repo_health/index/static/assets/css/styles.css b/repo_health/index/static/client/assets/css/styles.css similarity index 100% rename from repo_health/index/static/assets/css/styles.css rename to repo_health/index/static/client/assets/css/styles.css diff --git a/repo_health/index/static/assets/vendor/bootstrap.min.css b/repo_health/index/static/client/assets/vendor/bootstrap.min.css similarity index 100% rename from repo_health/index/static/assets/vendor/bootstrap.min.css rename to repo_health/index/static/client/assets/vendor/bootstrap.min.css diff --git a/repo_health/index/static/src/app.js b/repo_health/index/static/client/src/app.js similarity index 100% rename from repo_health/index/static/src/app.js rename to repo_health/index/static/client/src/app.js diff --git a/repo_health/index/static/src/components/components.module.js b/repo_health/index/static/client/src/components/components.module.js similarity index 100% rename from repo_health/index/static/src/components/components.module.js rename to repo_health/index/static/client/src/components/components.module.js diff --git a/repo_health/index/static/src/components/search/search.component.js b/repo_health/index/static/client/src/components/search/search.component.js similarity index 100% rename from repo_health/index/static/src/components/search/search.component.js rename to repo_health/index/static/client/src/components/search/search.component.js diff --git a/repo_health/index/static/src/components/search/search.controller.js b/repo_health/index/static/client/src/components/search/search.controller.js similarity index 100% rename from repo_health/index/static/src/components/search/search.controller.js rename to repo_health/index/static/client/src/components/search/search.controller.js diff --git a/repo_health/index/static/src/components/search/search.html b/repo_health/index/static/client/src/components/search/search.html similarity index 100% rename from repo_health/index/static/src/components/search/search.html rename to repo_health/index/static/client/src/components/search/search.html diff --git a/repo_health/index/static/src/components/search/search.module.js b/repo_health/index/static/client/src/components/search/search.module.js similarity index 100% rename from repo_health/index/static/src/components/search/search.module.js rename to repo_health/index/static/client/src/components/search/search.module.js diff --git a/repo_health/index/static/src/components/search/search.spec.js b/repo_health/index/static/client/src/components/search/search.spec.js similarity index 100% rename from repo_health/index/static/src/components/search/search.spec.js rename to repo_health/index/static/client/src/components/search/search.spec.js diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index 99ba0e0..7fa4fcd 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -14,9 +14,29 @@ }, "devDependencies": { "angular-mocks": "^1.6.2", + "babel-core": "^6.22.1", + "babel-loader": "^6.2.10", + "babel-plugin-angularjs-annotate": "^0.7.0", + "babel-plugin-transform-class-properties": "^6.22.0", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-plugin-transform-object-assign": "^6.22.0", + "babel-plugin-transform-object-rest-spread": "^6.22.0", + "babel-polyfill": "^6.22.0", + "babel-preset-es2015": "^6.22.0", + "css-loader": "^0.26.1", + "del": "^2.2.2", + "gulp": "^3.9.1", + "gulp-change": "~1.0.0", + "html-loader": "^0.4.4", + "html-webpack-plugin": "^2.28.0", "jasmine-core": "^2.5.2", "karma": "^1.4.1", "karma-chrome-launcher": "^2.0.0", - "karma-jasmine": "^1.1.0" + "karma-jasmine": "^1.1.0", + "progress-bar-webpack-plugin": "^1.9.3", + "style-loader": "^0.13.1", + "webpack": "^2.2.1", + "webpack-dev-server": "^2.3.0", + "yargs": "^6.6.0" } } diff --git a/repo_health/index/static/webpack.config.js b/repo_health/index/static/webpack.config.js new file mode 100644 index 0000000..900f36d --- /dev/null +++ b/repo_health/index/static/webpack.config.js @@ -0,0 +1,101 @@ +const webpack = require('webpack'); +const ProgressBarPlugin = require('progress-bar-webpack-plugin'); +const path = require('path'); +const { argv } = require('yargs'); + +const baseConfig = { + entry: { + app: ['./client/src/app.js'] + }, + + output: { + path: path.join(__dirname, '/dist/js'), + publicPath: 'js/', + filename: '[name].js' + }, + + resolve: { + modules: [ + path.resolve('./client/src'), + path.resolve('./client/assets'), + path.resolve('./node_modules') + ], + extensions: ['.js'] + }, + + module: { + rules: [ + { + test: /\.js$/, + include: [ + path.resolve(__dirname, 'client/src'), + ], + loader: 'babel-loader' + }, + { + test: /\.html$/, + loader: 'html-loader' + }, + { + test: /\.css$/, + use: ['style-loader', 'css-loader'] + } + ] + }, + + plugins: [ + new webpack.optimize.CommonsChunkPlugin({ + name: 'vendor', + minChunks(module) { + return module.context && module.context.indexOf('node_modules') !== -1; + } + }), + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + 'window.jQuery': 'jquery' + }), + new webpack.NoEmitOnErrorsPlugin(), + new ProgressBarPlugin() + ], + + node: { + fs: 'empty', + net: 'empty' + } +}; + +const developmentConfig = Object.assign({}, baseConfig, { + devtool: 'cheap-module-source-map', + cache: true, + plugins: [ + ...baseConfig.plugins, + new webpack.LoaderOptionsPlugin({ + debug: true + }) + ] +}); + +const productionConfig = Object.assign({}, baseConfig, { + plugins: [ + ...baseConfig.plugins, + + new webpack.LoaderOptionsPlugin({ + minimize: true, + debug: false + }), + + new webpack.optimize.UglifyJsPlugin({ + compress: { + warnings: false, + drop_console: true, + unused: true + }, + sourceMap: false, + minimize: true, + mangle: true + }) + ] +}); + +module.exports = argv.env === 'prod' ? productionConfig : developmentConfig; From 235db4c411169276f2a381ee74e1b49b458a144f Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 22 Feb 2017 14:40:10 -0600 Subject: [PATCH 19/99] Added webpack server config --- .../index/static/dist/assets/css/styles.css | 26 +++++++++++ .../dist/assets/vendor/bootstrap.min.css | 11 +++++ repo_health/index/static/gulpfile.js | 15 +++++++ repo_health/index/static/package.json | 2 +- repo_health/index/static/properties.json | 4 ++ repo_health/index/static/webpack.server.js | 44 +++++++++++++++++++ repo_health/index/templates/index.html | 3 ++ 7 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 repo_health/index/static/dist/assets/css/styles.css create mode 100644 repo_health/index/static/dist/assets/vendor/bootstrap.min.css create mode 100644 repo_health/index/static/gulpfile.js create mode 100644 repo_health/index/static/properties.json create mode 100644 repo_health/index/static/webpack.server.js diff --git a/repo_health/index/static/dist/assets/css/styles.css b/repo_health/index/static/dist/assets/css/styles.css new file mode 100644 index 0000000..38d967e --- /dev/null +++ b/repo_health/index/static/dist/assets/css/styles.css @@ -0,0 +1,26 @@ +/* +* styles.css - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This file holds the general css for the application +*/ + +.search-repo { + width: 75%; + height: 200px; + position: absolute; + top: 0; + bottom: 15%; + left: 0; + right: 0; + margin: auto; +} + +.search-button { + margin-top: 15px; +} \ No newline at end of file diff --git a/repo_health/index/static/dist/assets/vendor/bootstrap.min.css b/repo_health/index/static/dist/assets/vendor/bootstrap.min.css new file mode 100644 index 0000000..afeeb3b --- /dev/null +++ b/repo_health/index/static/dist/assets/vendor/bootstrap.min.css @@ -0,0 +1,11 @@ +@import url("https://fonts.googleapis.com/css?family=Lato:400,700,400italic");/*! + * bootswatch v3.3.7 + * Homepage: http://bootswatch.com + * Copyright 2012-2016 Thomas Park + * Licensed under MIT + * Based on Bootstrap +*//*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;-webkit-box-shadow:none !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:15px;line-height:1.42857143;color:#2c3e50;background-color:#ffffff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#18bc9c;text-decoration:none}a:hover,a:focus{color:#18bc9c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#ffffff;border:1px solid #ecf0f1;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:21px;margin-bottom:21px;border:0;border-top:1px solid #ecf0f1}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#b4bcc2}h1,.h1,h2,.h2,h3,.h3{margin-top:21px;margin-bottom:10.5px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10.5px;margin-bottom:10.5px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:39px}h2,.h2{font-size:32px}h3,.h3{font-size:26px}h4,.h4{font-size:19px}h5,.h5{font-size:15px}h6,.h6{font-size:13px}p{margin:0 0 10.5px}.lead{margin-bottom:21px;font-size:17px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:22.5px}}small,.small{font-size:86%}mark,.mark{background-color:#f39c12;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#b4bcc2}.text-primary{color:#2c3e50}a.text-primary:hover,a.text-primary:focus{color:#1a242f}.text-success{color:#ffffff}a.text-success:hover,a.text-success:focus{color:#e6e6e6}.text-info{color:#ffffff}a.text-info:hover,a.text-info:focus{color:#e6e6e6}.text-warning{color:#ffffff}a.text-warning:hover,a.text-warning:focus{color:#e6e6e6}.text-danger{color:#ffffff}a.text-danger:hover,a.text-danger:focus{color:#e6e6e6}.bg-primary{color:#fff;background-color:#2c3e50}a.bg-primary:hover,a.bg-primary:focus{background-color:#1a242f}.bg-success{background-color:#18bc9c}a.bg-success:hover,a.bg-success:focus{background-color:#128f76}.bg-info{background-color:#3498db}a.bg-info:hover,a.bg-info:focus{background-color:#217dbb}.bg-warning{background-color:#f39c12}a.bg-warning:hover,a.bg-warning:focus{background-color:#c87f0a}.bg-danger{background-color:#e74c3c}a.bg-danger:hover,a.bg-danger:focus{background-color:#d62c1a}.page-header{padding-bottom:9.5px;margin:42px 0 21px;border-bottom:1px solid transparent}ul,ol{margin-top:0;margin-bottom:10.5px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:21px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #b4bcc2}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10.5px 21px;margin:0 0 21px;font-size:18.75px;border-left:5px solid #ecf0f1}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#b4bcc2}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #ecf0f1;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:21px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#ffffff;background-color:#333333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;font-weight:bold;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:10px;margin:0 0 10.5px;font-size:14px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#7b8a8b;background-color:#ecf0f1;border:1px solid #cccccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0%}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0%}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0%}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0%}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#b4bcc2;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:21px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ecf0f1}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ecf0f1}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ecf0f1}.table .table{background-color:#ffffff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ecf0f1}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ecf0f1}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#ecf0f1}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#ecf0f1}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#dde4e6}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#18bc9c}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#15a589}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#3498db}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#258cd1}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#f39c12}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#e08e0b}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#e74c3c}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#e43725}.table-responsive{overflow-x:auto;min-height:0.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15.75px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ecf0f1}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:21px;font-size:22.5px;line-height:inherit;color:#2c3e50;border:0;border-bottom:1px solid transparent}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:11px;font-size:15px;line-height:1.42857143;color:#2c3e50}.form-control{display:block;width:100%;height:45px;padding:10px 15px;font-size:15px;line-height:1.42857143;color:#2c3e50;background-color:#ffffff;background-image:none;border:1px solid #dce4ec;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#2c3e50;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(44,62,80,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(44,62,80,0.6)}.form-control::-moz-placeholder{color:#acb6c0;opacity:1}.form-control:-ms-input-placeholder{color:#acb6c0}.form-control::-webkit-input-placeholder{color:#acb6c0}.form-control::-ms-expand{border:0;background-color:transparent}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#ecf0f1;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type="date"].form-control,input[type="time"].form-control,input[type="datetime-local"].form-control,input[type="month"].form-control{line-height:45px}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm,.input-group-sm input[type="date"],.input-group-sm input[type="time"],.input-group-sm input[type="datetime-local"],.input-group-sm input[type="month"]{line-height:35px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg,.input-group-lg input[type="date"],.input-group-lg input[type="time"],.input-group-lg input[type="datetime-local"],.input-group-lg input[type="month"]{line-height:66px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:21px;padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:11px;padding-bottom:11px;margin-bottom:0;min-height:36px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm{height:35px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}select.input-sm{height:35px;line-height:35px}textarea.input-sm,select[multiple].input-sm{height:auto}.form-group-sm .form-control{height:35px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:35px;line-height:35px}.form-group-sm textarea.form-control,.form-group-sm select[multiple].form-control{height:auto}.form-group-sm .form-control-static{height:35px;min-height:34px;padding:7px 9px;font-size:13px;line-height:1.5}.input-lg{height:66px;padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}select.input-lg{height:66px;line-height:66px}textarea.input-lg,select[multiple].input-lg{height:auto}.form-group-lg .form-control{height:66px;padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:66px;line-height:66px}.form-group-lg textarea.form-control,.form-group-lg select[multiple].form-control{height:auto}.form-group-lg .form-control-static{height:66px;min-height:40px;padding:19px 27px;font-size:19px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:56.25px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:45px;height:45px;line-height:45px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback,.input-group-lg+.form-control-feedback,.form-group-lg .form-control+.form-control-feedback{width:66px;height:66px;line-height:66px}.input-sm+.form-control-feedback,.input-group-sm+.form-control-feedback,.form-group-sm .form-control+.form-control-feedback{width:35px;height:35px;line-height:35px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#ffffff}.has-success .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-success .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#18bc9c}.has-success .form-control-feedback{color:#ffffff}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#ffffff}.has-warning .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-warning .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#f39c12}.has-warning .form-control-feedback{color:#ffffff}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#ffffff}.has-error .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-error .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#e74c3c}.has-error .form-control-feedback{color:#ffffff}.has-feedback label~.form-control-feedback{top:26px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#597ea2}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:11px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:32px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:11px}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:19px;font-size:19px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:7px;font-size:13px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:10px 15px;font-size:15px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#ffffff;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#ffffff;background-color:#95a5a6;border-color:#95a5a6}.btn-default:focus,.btn-default.focus{color:#ffffff;background-color:#798d8f;border-color:#566566}.btn-default:hover{color:#ffffff;background-color:#798d8f;border-color:#74898a}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#ffffff;background-color:#798d8f;border-color:#74898a}.btn-default:active:hover,.btn-default.active:hover,.open>.dropdown-toggle.btn-default:hover,.btn-default:active:focus,.btn-default.active:focus,.open>.dropdown-toggle.btn-default:focus,.btn-default:active.focus,.btn-default.active.focus,.open>.dropdown-toggle.btn-default.focus{color:#ffffff;background-color:#687b7c;border-color:#566566}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus{background-color:#95a5a6;border-color:#95a5a6}.btn-default .badge{color:#95a5a6;background-color:#ffffff}.btn-primary{color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.btn-primary:focus,.btn-primary.focus{color:#ffffff;background-color:#1a242f;border-color:#000000}.btn-primary:hover{color:#ffffff;background-color:#1a242f;border-color:#161f29}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#ffffff;background-color:#1a242f;border-color:#161f29}.btn-primary:active:hover,.btn-primary.active:hover,.open>.dropdown-toggle.btn-primary:hover,.btn-primary:active:focus,.btn-primary.active:focus,.open>.dropdown-toggle.btn-primary:focus,.btn-primary:active.focus,.btn-primary.active.focus,.open>.dropdown-toggle.btn-primary.focus{color:#ffffff;background-color:#0d1318;border-color:#000000}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus{background-color:#2c3e50;border-color:#2c3e50}.btn-primary .badge{color:#2c3e50;background-color:#ffffff}.btn-success{color:#ffffff;background-color:#18bc9c;border-color:#18bc9c}.btn-success:focus,.btn-success.focus{color:#ffffff;background-color:#128f76;border-color:#0a4b3e}.btn-success:hover{color:#ffffff;background-color:#128f76;border-color:#11866f}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#ffffff;background-color:#128f76;border-color:#11866f}.btn-success:active:hover,.btn-success.active:hover,.open>.dropdown-toggle.btn-success:hover,.btn-success:active:focus,.btn-success.active:focus,.open>.dropdown-toggle.btn-success:focus,.btn-success:active.focus,.btn-success.active.focus,.open>.dropdown-toggle.btn-success.focus{color:#ffffff;background-color:#0e6f5c;border-color:#0a4b3e}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus{background-color:#18bc9c;border-color:#18bc9c}.btn-success .badge{color:#18bc9c;background-color:#ffffff}.btn-info{color:#ffffff;background-color:#3498db;border-color:#3498db}.btn-info:focus,.btn-info.focus{color:#ffffff;background-color:#217dbb;border-color:#16527a}.btn-info:hover{color:#ffffff;background-color:#217dbb;border-color:#2077b2}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#ffffff;background-color:#217dbb;border-color:#2077b2}.btn-info:active:hover,.btn-info.active:hover,.open>.dropdown-toggle.btn-info:hover,.btn-info:active:focus,.btn-info.active:focus,.open>.dropdown-toggle.btn-info:focus,.btn-info:active.focus,.btn-info.active.focus,.open>.dropdown-toggle.btn-info.focus{color:#ffffff;background-color:#1c699d;border-color:#16527a}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus{background-color:#3498db;border-color:#3498db}.btn-info .badge{color:#3498db;background-color:#ffffff}.btn-warning{color:#ffffff;background-color:#f39c12;border-color:#f39c12}.btn-warning:focus,.btn-warning.focus{color:#ffffff;background-color:#c87f0a;border-color:#7f5006}.btn-warning:hover{color:#ffffff;background-color:#c87f0a;border-color:#be780a}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#ffffff;background-color:#c87f0a;border-color:#be780a}.btn-warning:active:hover,.btn-warning.active:hover,.open>.dropdown-toggle.btn-warning:hover,.btn-warning:active:focus,.btn-warning.active:focus,.open>.dropdown-toggle.btn-warning:focus,.btn-warning:active.focus,.btn-warning.active.focus,.open>.dropdown-toggle.btn-warning.focus{color:#ffffff;background-color:#a66908;border-color:#7f5006}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus{background-color:#f39c12;border-color:#f39c12}.btn-warning .badge{color:#f39c12;background-color:#ffffff}.btn-danger{color:#ffffff;background-color:#e74c3c;border-color:#e74c3c}.btn-danger:focus,.btn-danger.focus{color:#ffffff;background-color:#d62c1a;border-color:#921e12}.btn-danger:hover{color:#ffffff;background-color:#d62c1a;border-color:#cd2a19}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#ffffff;background-color:#d62c1a;border-color:#cd2a19}.btn-danger:active:hover,.btn-danger.active:hover,.open>.dropdown-toggle.btn-danger:hover,.btn-danger:active:focus,.btn-danger.active:focus,.open>.dropdown-toggle.btn-danger:focus,.btn-danger:active.focus,.btn-danger.active.focus,.open>.dropdown-toggle.btn-danger.focus{color:#ffffff;background-color:#b62516;border-color:#921e12}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus{background-color:#e74c3c;border-color:#e74c3c}.btn-danger .badge{color:#e74c3c;background-color:#ffffff}.btn-link{color:#18bc9c;font-weight:normal;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#18bc9c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#b4bcc2;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:13px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height, visibility;-o-transition-property:height, visibility;transition-property:height, visibility;-webkit-transition-duration:0.35s;-o-transition-duration:0.35s;transition-duration:0.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid \9;border-right:4px solid transparent;border-left:4px solid transparent}.dropup,.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:15px;text-align:left;background-color:#ffffff;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);-webkit-background-clip:padding-box;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#7b8a8b;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#ffffff;background-color:#2c3e50}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#2c3e50}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#b4bcc2}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:13px;line-height:1.42857143;color:#b4bcc2;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid \9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn input[type="radio"],[data-toggle="buttons"]>.btn-group>.btn input[type="radio"],[data-toggle="buttons"]>.btn input[type="checkbox"],[data-toggle="buttons"]>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:66px;padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:66px;line-height:66px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:35px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:35px;line-height:35px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:10px 15px;font-size:15px;font-weight:normal;line-height:1;color:#2c3e50;text-align:center;background-color:#ecf0f1;border:1px solid #dce4ec;border-radius:4px}.input-group-addon.input-sm{padding:6px 9px;font-size:13px;border-radius:3px}.input-group-addon.input-lg{padding:18px 27px;font-size:19px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#ecf0f1}.nav>li.disabled>a{color:#b4bcc2}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#b4bcc2;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#ecf0f1;border-color:#18bc9c}.nav .nav-divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ecf0f1}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#ecf0f1 #ecf0f1 #ecf0f1}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#2c3e50;background-color:#ffffff;border:1px solid #ecf0f1;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ecf0f1}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ecf0f1;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#ffffff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#ffffff;background-color:#2c3e50}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ecf0f1}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ecf0f1;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#ffffff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:60px;margin-bottom:21px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:19.5px 15px;font-size:19px;line-height:21px;height:60px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:13px;margin-bottom:13px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:9.75px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:21px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:21px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:19.5px;padding-bottom:19.5px}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:7.5px;margin-bottom:7.5px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:7.5px;margin-bottom:7.5px}.navbar-btn.btn-sm{margin-top:12.5px;margin-bottom:12.5px}.navbar-btn.btn-xs{margin-top:19px;margin-bottom:19px}.navbar-text{margin-top:19.5px;margin-bottom:19.5px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}}@media (min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#2c3e50;border-color:transparent}.navbar-default .navbar-brand{color:#ffffff}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-text{color:#ffffff}.navbar-default .navbar-nav>li>a{color:#ffffff}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#ffffff;background-color:#1a242f}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#1a242f}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#1a242f}.navbar-default .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:transparent}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#1a242f;color:#ffffff}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#1a242f}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-default .navbar-link{color:#ffffff}.navbar-default .navbar-link:hover{color:#18bc9c}.navbar-default .btn-link{color:#ffffff}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#18bc9c}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#cccccc}.navbar-inverse{background-color:#18bc9c;border-color:transparent}.navbar-inverse .navbar-brand{color:#ffffff}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-text{color:#ffffff}.navbar-inverse .navbar-nav>li>a{color:#ffffff}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#ffffff;background-color:#15a589}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#128f76}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#128f76}.navbar-inverse .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#149c82}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#15a589;color:#ffffff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#15a589}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-inverse .navbar-link{color:#ffffff}.navbar-inverse .navbar-link:hover{color:#2c3e50}.navbar-inverse .btn-link{color:#ffffff}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#2c3e50}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#cccccc}.breadcrumb{padding:8px 15px;margin-bottom:21px;list-style:none;background-color:#ecf0f1;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#cccccc}.breadcrumb>.active{color:#95a5a6}.pagination{display:inline-block;padding-left:0;margin:21px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:10px 15px;line-height:1.42857143;text-decoration:none;color:#ffffff;background-color:#18bc9c;border:1px solid transparent;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{z-index:2;color:#ffffff;background-color:#0f7864;border-color:transparent}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:3;color:#ffffff;background-color:#0f7864;border-color:transparent;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#ecf0f1;background-color:#3be6c4;border-color:transparent;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:18px 27px;font-size:19px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:6px 9px;font-size:13px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:21px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#18bc9c;border:1px solid transparent;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#0f7864}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#ffffff;background-color:#18bc9c;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#ffffff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#ffffff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#95a5a6}.label-default[href]:hover,.label-default[href]:focus{background-color:#798d8f}.label-primary{background-color:#2c3e50}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#1a242f}.label-success{background-color:#18bc9c}.label-success[href]:hover,.label-success[href]:focus{background-color:#128f76}.label-info{background-color:#3498db}.label-info[href]:hover,.label-info[href]:focus{background-color:#217dbb}.label-warning{background-color:#f39c12}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#c87f0a}.label-danger{background-color:#e74c3c}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#d62c1a}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:13px;font-weight:bold;color:#ffffff;line-height:1;vertical-align:middle;white-space:nowrap;text-align:center;background-color:#2c3e50;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge,.btn-group-xs>.btn .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#2c3e50;background-color:#ffffff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#ecf0f1}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:23px;font-weight:200}.jumbotron>hr{border-top-color:#cfd9db}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px;padding-left:15px;padding-right:15px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:68px}}.thumbnail{display:block;padding:4px;margin-bottom:21px;line-height:1.42857143;background-color:#ffffff;border:1px solid #ecf0f1;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#18bc9c}.thumbnail .caption{padding:9px;color:#2c3e50}.alert{padding:15px;margin-bottom:21px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#18bc9c;border-color:#18bc9c;color:#ffffff}.alert-success hr{border-top-color:#15a589}.alert-success .alert-link{color:#e6e6e6}.alert-info{background-color:#3498db;border-color:#3498db;color:#ffffff}.alert-info hr{border-top-color:#258cd1}.alert-info .alert-link{color:#e6e6e6}.alert-warning{background-color:#f39c12;border-color:#f39c12;color:#ffffff}.alert-warning hr{border-top-color:#e08e0b}.alert-warning .alert-link{color:#e6e6e6}.alert-danger{background-color:#e74c3c;border-color:#e74c3c;color:#ffffff}.alert-danger hr{border-top-color:#e43725}.alert-danger .alert-link{color:#e6e6e6}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:21px;margin-bottom:21px;background-color:#ecf0f1;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:13px;line-height:21px;color:#ffffff;text-align:center;background-color:#2c3e50;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#18bc9c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#3498db}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f39c12}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#e74c3c}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#ffffff;border:1px solid #ecf0f1}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333333}a.list-group-item:hover,button.list-group-item:hover,a.list-group-item:focus,button.list-group-item:focus{text-decoration:none;color:#555555;background-color:#ecf0f1}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#ecf0f1;color:#b4bcc2;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#b4bcc2}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#8aa4be}.list-group-item-success{color:#ffffff;background-color:#18bc9c}a.list-group-item-success,button.list-group-item-success{color:#ffffff}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,button.list-group-item-success:hover,a.list-group-item-success:focus,button.list-group-item-success:focus{color:#ffffff;background-color:#15a589}a.list-group-item-success.active,button.list-group-item-success.active,a.list-group-item-success.active:hover,button.list-group-item-success.active:hover,a.list-group-item-success.active:focus,button.list-group-item-success.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-info{color:#ffffff;background-color:#3498db}a.list-group-item-info,button.list-group-item-info{color:#ffffff}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,button.list-group-item-info:hover,a.list-group-item-info:focus,button.list-group-item-info:focus{color:#ffffff;background-color:#258cd1}a.list-group-item-info.active,button.list-group-item-info.active,a.list-group-item-info.active:hover,button.list-group-item-info.active:hover,a.list-group-item-info.active:focus,button.list-group-item-info.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-warning{color:#ffffff;background-color:#f39c12}a.list-group-item-warning,button.list-group-item-warning{color:#ffffff}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,button.list-group-item-warning:hover,a.list-group-item-warning:focus,button.list-group-item-warning:focus{color:#ffffff;background-color:#e08e0b}a.list-group-item-warning.active,button.list-group-item-warning.active,a.list-group-item-warning.active:hover,button.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus,button.list-group-item-warning.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-danger{color:#ffffff;background-color:#e74c3c}a.list-group-item-danger,button.list-group-item-danger{color:#ffffff}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,button.list-group-item-danger:hover,a.list-group-item-danger:focus,button.list-group-item-danger:focus{color:#ffffff;background-color:#e43725}a.list-group-item-danger.active,button.list-group-item-danger.active,a.list-group-item-danger.active:hover,button.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus,button.list-group-item-danger.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:21px;background-color:#ffffff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:17px;color:inherit}.panel-title>a,.panel-title>small,.panel-title>.small,.panel-title>small>a,.panel-title>.small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#ecf0f1;border-top:1px solid #ecf0f1;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-left:15px;padding-right:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ecf0f1}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:21px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ecf0f1}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ecf0f1}.panel-default{border-color:#ecf0f1}.panel-default>.panel-heading{color:#2c3e50;background-color:#ecf0f1;border-color:#ecf0f1}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ecf0f1}.panel-default>.panel-heading .badge{color:#ecf0f1;background-color:#2c3e50}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ecf0f1}.panel-primary{border-color:#2c3e50}.panel-primary>.panel-heading{color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#2c3e50}.panel-primary>.panel-heading .badge{color:#2c3e50;background-color:#ffffff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#2c3e50}.panel-success{border-color:#18bc9c}.panel-success>.panel-heading{color:#ffffff;background-color:#18bc9c;border-color:#18bc9c}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#18bc9c}.panel-success>.panel-heading .badge{color:#18bc9c;background-color:#ffffff}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#18bc9c}.panel-info{border-color:#3498db}.panel-info>.panel-heading{color:#ffffff;background-color:#3498db;border-color:#3498db}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#3498db}.panel-info>.panel-heading .badge{color:#3498db;background-color:#ffffff}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#3498db}.panel-warning{border-color:#f39c12}.panel-warning>.panel-heading{color:#ffffff;background-color:#f39c12;border-color:#f39c12}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f39c12}.panel-warning>.panel-heading .badge{color:#f39c12;background-color:#ffffff}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f39c12}.panel-danger{border-color:#e74c3c}.panel-danger>.panel-heading{color:#ffffff;background-color:#e74c3c;border-color:#e74c3c}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#e74c3c}.panel-danger>.panel-heading .badge{color:#e74c3c;background-color:#ffffff}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#e74c3c}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#ecf0f1;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:22.5px;font-weight:bold;line-height:1;color:#000000;text-shadow:none;opacity:0.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);-o-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#ffffff;border:1px solid #999999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);-webkit-background-clip:padding-box;background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:0.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:20px}.modal-footer{padding:20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:13px;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:0.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;background-color:#000000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.top-left .tooltip-arrow{bottom:0;right:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:15px;background-color:#ffffff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:15px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999999;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.next,.carousel-inner>.item.active.right{-webkit-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);left:0}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{-webkit-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:0.5;filter:alpha(opacity=50);font-size:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);background-color:rgba(0,0,0,0)}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-webkit-gradient(linear, left top, right top, from(rgba(0,0,0,0.5)), to(rgba(0,0,0,0.0001)));background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-webkit-gradient(linear, left top, right top, from(rgba(0,0,0,0.0001)), to(rgba(0,0,0,0.5)));background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;margin-top:-10px;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #ffffff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#ffffff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-header:before,.modal-header:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-header:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table !important}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table !important}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table !important}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table !important}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table !important}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}.navbar{border-width:0}.navbar-default .badge{background-color:#fff;color:#2c3e50}.navbar-inverse .badge{background-color:#fff;color:#18bc9c}.navbar-brand{line-height:1}.btn{border-width:2px}.btn:active{-webkit-box-shadow:none;box-shadow:none}.btn-group.open .dropdown-toggle{-webkit-box-shadow:none;box-shadow:none}.text-primary,.text-primary:hover{color:#2c3e50}.text-success,.text-success:hover{color:#18bc9c}.text-danger,.text-danger:hover{color:#e74c3c}.text-warning,.text-warning:hover{color:#f39c12}.text-info,.text-info:hover{color:#3498db}table a:not(.btn),.table a:not(.btn){text-decoration:underline}table .dropdown-menu a,.table .dropdown-menu a{text-decoration:none}table .success,.table .success,table .warning,.table .warning,table .danger,.table .danger,table .info,.table .info{color:#fff}table .success>th>a,.table .success>th>a,table .warning>th>a,.table .warning>th>a,table .danger>th>a,.table .danger>th>a,table .info>th>a,.table .info>th>a,table .success>td>a,.table .success>td>a,table .warning>td>a,.table .warning>td>a,table .danger>td>a,.table .danger>td>a,table .info>td>a,.table .info>td>a,table .success>a,.table .success>a,table .warning>a,.table .warning>a,table .danger>a,.table .danger>a,table .info>a,.table .info>a{color:#fff}table>thead>tr>th,.table>thead>tr>th,table>tbody>tr>th,.table>tbody>tr>th,table>tfoot>tr>th,.table>tfoot>tr>th,table>thead>tr>td,.table>thead>tr>td,table>tbody>tr>td,.table>tbody>tr>td,table>tfoot>tr>td,.table>tfoot>tr>td{border:none}table-bordered>thead>tr>th,.table-bordered>thead>tr>th,table-bordered>tbody>tr>th,.table-bordered>tbody>tr>th,table-bordered>tfoot>tr>th,.table-bordered>tfoot>tr>th,table-bordered>thead>tr>td,.table-bordered>thead>tr>td,table-bordered>tbody>tr>td,.table-bordered>tbody>tr>td,table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ecf0f1}.form-control,input{border-width:2px;-webkit-box-shadow:none;box-shadow:none}.form-control:focus,input:focus{-webkit-box-shadow:none;box-shadow:none}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label,.has-warning .form-control-feedback{color:#f39c12}.has-warning .form-control,.has-warning .form-control:focus{border:2px solid #f39c12}.has-warning .input-group-addon{border-color:#f39c12}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label,.has-error .form-control-feedback{color:#e74c3c}.has-error .form-control,.has-error .form-control:focus{border:2px solid #e74c3c}.has-error .input-group-addon{border-color:#e74c3c}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label,.has-success .form-control-feedback{color:#18bc9c}.has-success .form-control,.has-success .form-control:focus{border:2px solid #18bc9c}.has-success .input-group-addon{border-color:#18bc9c}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{border-color:transparent}.pager a,.pager a:hover{color:#fff}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{background-color:#3be6c4}.close{color:#fff;text-decoration:none;opacity:0.4}.close:hover,.close:focus{color:#fff;opacity:1}.alert .alert-link{color:#fff;text-decoration:underline}.progress{height:10px;-webkit-box-shadow:none;box-shadow:none}.progress .progress-bar{font-size:10px;line-height:10px}.well{-webkit-box-shadow:none;box-shadow:none}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{border-color:#ecf0f1}a.list-group-item-success.active{background-color:#18bc9c}a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{background-color:#15a589}a.list-group-item-warning.active{background-color:#f39c12}a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{background-color:#e08e0b}a.list-group-item-danger.active{background-color:#e74c3c}a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{background-color:#e43725}.panel-default .close{color:#2c3e50}.modal .close{color:#2c3e50}.popover{color:#2c3e50} \ No newline at end of file diff --git a/repo_health/index/static/gulpfile.js b/repo_health/index/static/gulpfile.js new file mode 100644 index 0000000..98118e5 --- /dev/null +++ b/repo_health/index/static/gulpfile.js @@ -0,0 +1,15 @@ +const gulp = require('gulp'); +const del = require('del'); + +gulp.task('default', ['static']); + +gulp.task('static', ['clean'], () => + gulp.src([ + 'client/assets/**/*' + ], { base: './client' }) + .pipe(gulp.dest('dist')) +); + +gulp.task('clean', function () { + return del([ 'dist' ]); +}); \ No newline at end of file diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index 7fa4fcd..75d0278 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -4,6 +4,7 @@ "description": "Angular frontend for the repo health project.", "main": "index.js", "scripts": { + "start": "gulp && node webpack.server.js", "test": "./node_modules/karma/bin/karma start" }, "author": "", @@ -26,7 +27,6 @@ "css-loader": "^0.26.1", "del": "^2.2.2", "gulp": "^3.9.1", - "gulp-change": "~1.0.0", "html-loader": "^0.4.4", "html-webpack-plugin": "^2.28.0", "jasmine-core": "^2.5.2", diff --git a/repo_health/index/static/properties.json b/repo_health/index/static/properties.json new file mode 100644 index 0000000..83e04f4 --- /dev/null +++ b/repo_health/index/static/properties.json @@ -0,0 +1,4 @@ +{ + "RestHost": "localhost", + "RestLocation": "" +} diff --git a/repo_health/index/static/webpack.server.js b/repo_health/index/static/webpack.server.js new file mode 100644 index 0000000..8cdaa8f --- /dev/null +++ b/repo_health/index/static/webpack.server.js @@ -0,0 +1,44 @@ +const webpack = require('webpack'); +const WebpackDevServer = require('webpack-dev-server'); +const properties = require('./properties.json'); +const webpackConfig = require('./webpack.config'); + +const restHost = properties.RestHost; +const serverUrl = `http://${restHost}`; +const config = Object.create(webpackConfig); + +config.entry.app.unshift('webpack-dev-server/client?http://localhost:3000/', 'webpack/hot/dev-server'); +config.plugins.push(new webpack.HotModuleReplacementPlugin()); +config.watch = true; + +const compiler = webpack(config); + +const server = new WebpackDevServer(compiler, { + publicPath: `/${config.output.publicPath}`, + contentBase: 'dist', + hot: true, + stats: { + colors: true, + version: false, + hash: false, + timings: false, + chunks: false, + chunkModules: false + }, + proxy: [ + { + context: '/api/v1/**', + target: serverUrl + }, + { + context: (pathname, req) => pathname === '/' && req.method === 'GET', + target: `${serverUrl}:8000/app` + } + ] +}); + +server.listen(3000, 'localhost', err => { + if (err) { + console.log(err); + } +}); diff --git a/repo_health/index/templates/index.html b/repo_health/index/templates/index.html index 07abac5..f58c218 100644 --- a/repo_health/index/templates/index.html +++ b/repo_health/index/templates/index.html @@ -26,6 +26,9 @@

Repo Health Assessment

+ + + From 43b5933ac32eb8eaa375f8809ba38be6d2377a08 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 22 Feb 2017 14:43:16 -0600 Subject: [PATCH 20/99] Updated gitignore --- .gitignore | 1 + repo_health/index/static/client/src/app.js | 1 + repo_health/index/static/package.json | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6243ed2..6578ae9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,6 @@ .DS_Store local_settings.py node_modules +dist .vscode __pycache__ \ No newline at end of file diff --git a/repo_health/index/static/client/src/app.js b/repo_health/index/static/client/src/app.js index 57a3034..6500bac 100644 --- a/repo_health/index/static/client/src/app.js +++ b/repo_health/index/static/client/src/app.js @@ -10,6 +10,7 @@ * This is where the angular app gets bootstraped. * It will set up all the global configuration. */ +import angular from 'angular'; (function () { angular.module('repo-health', [ diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index 75d0278..933f00f 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -11,7 +11,8 @@ "license": "MIT", "dependencies": { "angular": "^1.6.2", - "angular-ui-router": "^0.4.2" + "angular-ui-router": "^0.4.2", + "jquery": "^3.1.0" }, "devDependencies": { "angular-mocks": "^1.6.2", From 39d710fce42a832c518b9b52e1faeb61db6f1fa3 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 22 Feb 2017 14:46:53 -0600 Subject: [PATCH 21/99] Updated index.html --- repo_health/index/templates/index.html | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/repo_health/index/templates/index.html b/repo_health/index/templates/index.html index f58c218..aab2e5a 100644 --- a/repo_health/index/templates/index.html +++ b/repo_health/index/templates/index.html @@ -7,9 +7,8 @@ - - - + + {% comment %} @@ -25,16 +24,4 @@

Repo Health Assessment

- - - - - - - - - - - - From 567e516d9561ef8a880773c0711a0e044051dfbb Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 22 Feb 2017 19:07:13 -0600 Subject: [PATCH 22/99] Converted code to ES6 and made in line with webpack --- .../src/components/components.module.js | 14 ++++++---- .../src/components/search/search.component.js | 26 +++++++++---------- .../components/search/search.controller.js | 25 ------------------ .../src/components/search/search.module.js | 20 ++++++++++---- .../client/src/{app.js => main.module.js} | 20 +++++++------- repo_health/index/static/webpack.config.js | 4 +-- repo_health/index/templates/index.html | 4 +-- 7 files changed, 51 insertions(+), 62 deletions(-) delete mode 100644 repo_health/index/static/client/src/components/search/search.controller.js rename repo_health/index/static/client/src/{app.js => main.module.js} (51%) diff --git a/repo_health/index/static/client/src/components/components.module.js b/repo_health/index/static/client/src/components/components.module.js index aaad30d..7ae1641 100644 --- a/repo_health/index/static/client/src/components/components.module.js +++ b/repo_health/index/static/client/src/components/components.module.js @@ -10,8 +10,12 @@ * This is the definitions for all of the components used in this application. */ -(function () { - angular.module('components', [ - 'components.search' - ]); -})(); \ No newline at end of file +import search from './search/search.module'; + +const components = angular + .module('components', [ + search + ]) + .name; + +export default components; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/search/search.component.js b/repo_health/index/static/client/src/components/search/search.component.js index 541242a..37711db 100644 --- a/repo_health/index/static/client/src/components/search/search.component.js +++ b/repo_health/index/static/client/src/components/search/search.component.js @@ -10,18 +10,16 @@ * This is the creation of the search component. */ -(function () { - var search = { - templateUrl: '/static/src/components/search/search.html', - controller: 'SearchController' - }; +import template from './search'; - angular.module('components.search') - .component('search', search) - .config(function($stateProvider) { - $stateProvider.state('search', { - url: '/search', - template: '' - }); - }); -})(); \ No newline at end of file +const searchComponent = { + template, + controller: class searchComponent { + + getStats() { + // Add service to get the statistics + } + } +}; + +export default searchComponent; diff --git a/repo_health/index/static/client/src/components/search/search.controller.js b/repo_health/index/static/client/src/components/search/search.controller.js deleted file mode 100644 index 22c1dde..0000000 --- a/repo_health/index/static/client/src/components/search/search.controller.js +++ /dev/null @@ -1,25 +0,0 @@ -/* -* search.controller.js - (C) Copyright - 2017 -* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. -* -* SPDX-License-Identifier: MIT -* -* Author(s) of this file: -* @bparish628 -* -* This is the controller that will be used in the search component. -* It will allow a user to search on a repo -*/ - -(function () { - angular.module('components.search') - .controller('SearchController', SearchController); - - function SearchController() { - var ctrl = this; - - ctrl.getStats = function() { - // Add service to get the statistics - } - } -})(); \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/search/search.module.js b/repo_health/index/static/client/src/components/search/search.module.js index a7aad6c..53ef6ec 100644 --- a/repo_health/index/static/client/src/components/search/search.module.js +++ b/repo_health/index/static/client/src/components/search/search.module.js @@ -9,9 +9,19 @@ * * This is the module definition for the search component */ +import searchComponent from './search.component'; -(function () { - angular.module('components.search', [ - 'ui.router' - ]); -})(); \ No newline at end of file +const components = angular + .module('components.search', []) + .component('search', searchComponent) + .config($stateProvider => { + 'ngInject'; + + $stateProvider.state('search', { + url: '/search', + template: '' + }) + }) + .name; + +export default components; \ No newline at end of file diff --git a/repo_health/index/static/client/src/app.js b/repo_health/index/static/client/src/main.module.js similarity index 51% rename from repo_health/index/static/client/src/app.js rename to repo_health/index/static/client/src/main.module.js index 6500bac..201b6eb 100644 --- a/repo_health/index/static/client/src/app.js +++ b/repo_health/index/static/client/src/main.module.js @@ -10,14 +10,16 @@ * This is where the angular app gets bootstraped. * It will set up all the global configuration. */ + import angular from 'angular'; +import uiRouter from 'angular-ui-router'; +import components from 'components/components.module.js'; -(function () { - angular.module('repo-health', [ - 'components' - ]) - .config((function($locationProvider, $urlRouterProvider) { - $locationProvider.hashPrefix(''); - $urlRouterProvider.otherwise('/search'); - })); -})(); +angular.module('repo-health', [ + uiRouter, + components +]) +.config((function($locationProvider, $urlRouterProvider) { + $locationProvider.hashPrefix(''); + $urlRouterProvider.otherwise('/search'); +})); diff --git a/repo_health/index/static/webpack.config.js b/repo_health/index/static/webpack.config.js index 900f36d..2514982 100644 --- a/repo_health/index/static/webpack.config.js +++ b/repo_health/index/static/webpack.config.js @@ -5,7 +5,7 @@ const { argv } = require('yargs'); const baseConfig = { entry: { - app: ['./client/src/app.js'] + app: ['./client/src/main.module.js'] }, output: { @@ -20,7 +20,7 @@ const baseConfig = { path.resolve('./client/assets'), path.resolve('./node_modules') ], - extensions: ['.js'] + extensions: ['.js', '.html'] }, module: { diff --git a/repo_health/index/templates/index.html b/repo_health/index/templates/index.html index aab2e5a..82304fe 100644 --- a/repo_health/index/templates/index.html +++ b/repo_health/index/templates/index.html @@ -4,8 +4,8 @@ Repo Health Assessment - - + + From 3bbbda040625f3992ef972dfe743ab9b8ac2aa47 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 22 Feb 2017 19:42:41 -0600 Subject: [PATCH 23/99] Added some more configuration --- repo_health/index/static/.babelrc | 11 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 ++++++++++++++++++ .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../index/static/client/assets/global.css | 2 + .../client/assets/{css => styles}/styles.css | 0 .../src/components/search/search.module.js | 2 +- .../index/static/client/src/main.module.js | 3 + repo_health/index/static/gulpfile.js | 15 - repo_health/index/static/package.json | 19 +- repo_health/index/static/properties.json | 2 +- repo_health/index/static/webpack.config.js | 11 +- repo_health/index/static/webpack.server.js | 2 +- repo_health/index/templates/index.html | 15 +- 16 files changed, 324 insertions(+), 46 deletions(-) create mode 100644 repo_health/index/static/.babelrc create mode 100644 repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.eot create mode 100644 repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.svg create mode 100644 repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.ttf create mode 100644 repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.woff create mode 100644 repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.woff2 create mode 100644 repo_health/index/static/client/assets/global.css rename repo_health/index/static/client/assets/{css => styles}/styles.css (100%) delete mode 100644 repo_health/index/static/gulpfile.js diff --git a/repo_health/index/static/.babelrc b/repo_health/index/static/.babelrc new file mode 100644 index 0000000..a86694a --- /dev/null +++ b/repo_health/index/static/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": [ + ["es2015", { "modules": false }] + ], + "plugins": [ + "transform-class-properties", + "transform-object-assign", + "transform-object-rest-spread", + "angularjs-annotate" + ] +} diff --git a/repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.eot b/repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..b93a4953fff68df523aa7656497ee339d6026d64 GIT binary patch literal 20127 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.ttf b/repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1413fc609ab6f21774de0cb7e01360095584f65b GIT binary patch literal 45404 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 G`u_lkUM?>H literal 0 HcmV?d00001 diff --git a/repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.woff2 b/repo_health/index/static/client/assets/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..64539b54c3751a6d9adb44c8e3a45ba5a73b77f0 GIT binary patch literal 18028 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 literal 0 HcmV?d00001 diff --git a/repo_health/index/static/client/assets/global.css b/repo_health/index/static/client/assets/global.css new file mode 100644 index 0000000..f826846 --- /dev/null +++ b/repo_health/index/static/client/assets/global.css @@ -0,0 +1,2 @@ +@import 'vendor/bootstrap.min.css'; +@import 'styles/styles.css'; \ No newline at end of file diff --git a/repo_health/index/static/client/assets/css/styles.css b/repo_health/index/static/client/assets/styles/styles.css similarity index 100% rename from repo_health/index/static/client/assets/css/styles.css rename to repo_health/index/static/client/assets/styles/styles.css diff --git a/repo_health/index/static/client/src/components/search/search.module.js b/repo_health/index/static/client/src/components/search/search.module.js index 53ef6ec..1bf19f9 100644 --- a/repo_health/index/static/client/src/components/search/search.module.js +++ b/repo_health/index/static/client/src/components/search/search.module.js @@ -16,7 +16,7 @@ const components = angular .component('search', searchComponent) .config($stateProvider => { 'ngInject'; - + $stateProvider.state('search', { url: '/search', template: '' diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index 201b6eb..92fdbeb 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -15,6 +15,9 @@ import angular from 'angular'; import uiRouter from 'angular-ui-router'; import components from 'components/components.module.js'; +//Styles +import 'global.css'; + angular.module('repo-health', [ uiRouter, components diff --git a/repo_health/index/static/gulpfile.js b/repo_health/index/static/gulpfile.js deleted file mode 100644 index 98118e5..0000000 --- a/repo_health/index/static/gulpfile.js +++ /dev/null @@ -1,15 +0,0 @@ -const gulp = require('gulp'); -const del = require('del'); - -gulp.task('default', ['static']); - -gulp.task('static', ['clean'], () => - gulp.src([ - 'client/assets/**/*' - ], { base: './client' }) - .pipe(gulp.dest('dist')) -); - -gulp.task('clean', function () { - return del([ 'dist' ]); -}); \ No newline at end of file diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index 933f00f..5e3cf05 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -3,10 +3,6 @@ "version": "1.0.0", "description": "Angular frontend for the repo health project.", "main": "index.js", - "scripts": { - "start": "gulp && node webpack.server.js", - "test": "./node_modules/karma/bin/karma start" - }, "author": "", "license": "MIT", "dependencies": { @@ -17,7 +13,7 @@ "devDependencies": { "angular-mocks": "^1.6.2", "babel-core": "^6.22.1", - "babel-loader": "^6.2.10", + "babel-loader": "^6.3.2", "babel-plugin-angularjs-annotate": "^0.7.0", "babel-plugin-transform-class-properties": "^6.22.0", "babel-plugin-transform-decorators-legacy": "^1.3.4", @@ -26,18 +22,23 @@ "babel-polyfill": "^6.22.0", "babel-preset-es2015": "^6.22.0", "css-loader": "^0.26.1", - "del": "^2.2.2", - "gulp": "^3.9.1", + "file-loader": "^0.10.0", "html-loader": "^0.4.4", "html-webpack-plugin": "^2.28.0", "jasmine-core": "^2.5.2", - "karma": "^1.4.1", + "karma": "^1.5.0", "karma-chrome-launcher": "^2.0.0", "karma-jasmine": "^1.1.0", "progress-bar-webpack-plugin": "^1.9.3", "style-loader": "^0.13.1", + "url-loader": "^0.5.7", "webpack": "^2.2.1", - "webpack-dev-server": "^2.3.0", + "webpack-dev-server": "^2.4.1", "yargs": "^6.6.0" + }, + "scripts": { + "prestart": "npm prune && npm install", + "start": "node webpack.server.js", + "test": "./node_modules/karma/bin/karma start" } } diff --git a/repo_health/index/static/properties.json b/repo_health/index/static/properties.json index 83e04f4..b172f66 100644 --- a/repo_health/index/static/properties.json +++ b/repo_health/index/static/properties.json @@ -1,4 +1,4 @@ { - "RestHost": "localhost", + "RestHost": "localhost:8000", "RestLocation": "" } diff --git a/repo_health/index/static/webpack.config.js b/repo_health/index/static/webpack.config.js index 2514982..40bb53a 100644 --- a/repo_health/index/static/webpack.config.js +++ b/repo_health/index/static/webpack.config.js @@ -39,7 +39,9 @@ const baseConfig = { { test: /\.css$/, use: ['style-loader', 'css-loader'] - } + }, + { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader:"url-loader?limit=10000&mimetype=application/font-woff" }, + { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" } ] }, @@ -57,12 +59,7 @@ const baseConfig = { }), new webpack.NoEmitOnErrorsPlugin(), new ProgressBarPlugin() - ], - - node: { - fs: 'empty', - net: 'empty' - } + ] }; const developmentConfig = Object.assign({}, baseConfig, { diff --git a/repo_health/index/static/webpack.server.js b/repo_health/index/static/webpack.server.js index 8cdaa8f..0f80d73 100644 --- a/repo_health/index/static/webpack.server.js +++ b/repo_health/index/static/webpack.server.js @@ -32,7 +32,7 @@ const server = new WebpackDevServer(compiler, { }, { context: (pathname, req) => pathname === '/' && req.method === 'GET', - target: `${serverUrl}:8000/app` + target: `${serverUrl}/app` } ] }); diff --git a/repo_health/index/templates/index.html b/repo_health/index/templates/index.html index 82304fe..7077e71 100644 --- a/repo_health/index/templates/index.html +++ b/repo_health/index/templates/index.html @@ -3,19 +3,7 @@ Repo Health Assessment - - - - - - - - {% comment %} - This template is rendered within Django, and this comment won't get rendered in the browser because it is wrapped in Django's comment tag. Django's and Angular's template language share the same curly braces for variable names. Like: {{ variable }}. Angular UI Router is used to get around this by rendering subsequent child templates in Angular only. This makes the frontend modular so it can be removed completely from the backend code, and not tied to Django specifically. - - Angular variables can still be rendered in this page by wrapping them in Django's verbatim tag, similar to this comment. All html is rendered as expected. - {% endcomment %}

Repo Health Assessment

@@ -24,4 +12,7 @@

Repo Health Assessment

+ + + From 40b327ff2ba48e34d97c978e43a1c7a296252e2a Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 22 Feb 2017 19:45:51 -0600 Subject: [PATCH 24/99] Cleanup of configuration --- repo_health/index/static/client/assets/global.css | 12 ++++++++++++ repo_health/index/static/properties.json | 3 +-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/repo_health/index/static/client/assets/global.css b/repo_health/index/static/client/assets/global.css index f826846..1669ae1 100644 --- a/repo_health/index/static/client/assets/global.css +++ b/repo_health/index/static/client/assets/global.css @@ -1,2 +1,14 @@ +/* +* component.module.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This file will contain all of the styles imported in the order they need to be +*/ + @import 'vendor/bootstrap.min.css'; @import 'styles/styles.css'; \ No newline at end of file diff --git a/repo_health/index/static/properties.json b/repo_health/index/static/properties.json index b172f66..06fdfd0 100644 --- a/repo_health/index/static/properties.json +++ b/repo_health/index/static/properties.json @@ -1,4 +1,3 @@ { - "RestHost": "localhost:8000", - "RestLocation": "" + "RestHost": "localhost:8000" } From 2b0fca9c6d128bcc6709589db99088018e5d194f Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 22 Feb 2017 19:56:46 -0600 Subject: [PATCH 25/99] Updated README --- README.md | 6 ++++-- .../static/client/src/components/search/search.module.js | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6a85fdb..f4aa5cd 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The Django web framework is used in the project to leverage quick development an Python 3.5 is recommended for this project. It can be downloaded and installed at [python.org](python.org). ## Frontend -The frontend source is written using Angular and Angular UI-Router. +The frontend source is written in ES2015 using [Angular](https://angularjs.org/). We are using [Bootstrap](http://getbootstrap.com/) for our styles. ## Development Environment A Unix dev environment is recommended because the setup instructions provided are known to work in these environments using a bash terminal. The instructions may work in a Windows bash terminal but have not been tested. @@ -70,7 +70,9 @@ An admin is available at [http://localhost:8000/admin/](http://localhost:8000/ad Run `python manage.py test --keepdb` to run the tests. The `--keepdb` is important so Django doesn't try to destroy the test database. ### Frontend configuration -From project root, `cd repo_health/index/static`. Run `npm install`. After successful install, [http://localhost:8000](http://localhost:8000) should display the Hello World page. +From project root, `cd repo_health/index/static`. + +Run `npm start` and go to [http://localhost:3000](http://localhost:3000) to view the application. To run ui tests, run `npm test` in the `repo_health/index/static` folder. diff --git a/repo_health/index/static/client/src/components/search/search.module.js b/repo_health/index/static/client/src/components/search/search.module.js index 1bf19f9..eab6046 100644 --- a/repo_health/index/static/client/src/components/search/search.module.js +++ b/repo_health/index/static/client/src/components/search/search.module.js @@ -9,6 +9,7 @@ * * This is the module definition for the search component */ + import searchComponent from './search.component'; const components = angular From 9c44ebaa882427f582bad6817adb09b687ba8ff0 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Thu, 23 Feb 2017 18:37:23 -0600 Subject: [PATCH 26/99] Removed old css files and add property for public path. --- .gitignore | 2 ++ .../index/static/dist/assets/css/styles.css | 26 ------------------- .../dist/assets/vendor/bootstrap.min.css | 11 -------- repo_health/index/static/properties.json | 3 ++- repo_health/index/static/webpack.server.js | 2 +- repo_health/index/templates/index.html | 6 +++-- 6 files changed, 9 insertions(+), 41 deletions(-) delete mode 100644 repo_health/index/static/dist/assets/css/styles.css delete mode 100644 repo_health/index/static/dist/assets/vendor/bootstrap.min.css diff --git a/.gitignore b/.gitignore index 6578ae9..3904c3e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,12 @@ *.sqlite* *.db *.pyc +*.log *~ .DS_Store local_settings.py node_modules dist .vscode +.idea __pycache__ \ No newline at end of file diff --git a/repo_health/index/static/dist/assets/css/styles.css b/repo_health/index/static/dist/assets/css/styles.css deleted file mode 100644 index 38d967e..0000000 --- a/repo_health/index/static/dist/assets/css/styles.css +++ /dev/null @@ -1,26 +0,0 @@ -/* -* styles.css - (C) Copyright - 2017 -* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. -* -* SPDX-License-Identifier: MIT -* -* Author(s) of this file: -* @bparish628 -* -* This file holds the general css for the application -*/ - -.search-repo { - width: 75%; - height: 200px; - position: absolute; - top: 0; - bottom: 15%; - left: 0; - right: 0; - margin: auto; -} - -.search-button { - margin-top: 15px; -} \ No newline at end of file diff --git a/repo_health/index/static/dist/assets/vendor/bootstrap.min.css b/repo_health/index/static/dist/assets/vendor/bootstrap.min.css deleted file mode 100644 index afeeb3b..0000000 --- a/repo_health/index/static/dist/assets/vendor/bootstrap.min.css +++ /dev/null @@ -1,11 +0,0 @@ -@import url("https://fonts.googleapis.com/css?family=Lato:400,700,400italic");/*! - * bootswatch v3.3.7 - * Homepage: http://bootswatch.com - * Copyright 2012-2016 Thomas Park - * Licensed under MIT - * Based on Bootstrap -*//*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;-webkit-box-shadow:none !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:15px;line-height:1.42857143;color:#2c3e50;background-color:#ffffff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#18bc9c;text-decoration:none}a:hover,a:focus{color:#18bc9c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#ffffff;border:1px solid #ecf0f1;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:21px;margin-bottom:21px;border:0;border-top:1px solid #ecf0f1}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#b4bcc2}h1,.h1,h2,.h2,h3,.h3{margin-top:21px;margin-bottom:10.5px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10.5px;margin-bottom:10.5px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:39px}h2,.h2{font-size:32px}h3,.h3{font-size:26px}h4,.h4{font-size:19px}h5,.h5{font-size:15px}h6,.h6{font-size:13px}p{margin:0 0 10.5px}.lead{margin-bottom:21px;font-size:17px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:22.5px}}small,.small{font-size:86%}mark,.mark{background-color:#f39c12;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#b4bcc2}.text-primary{color:#2c3e50}a.text-primary:hover,a.text-primary:focus{color:#1a242f}.text-success{color:#ffffff}a.text-success:hover,a.text-success:focus{color:#e6e6e6}.text-info{color:#ffffff}a.text-info:hover,a.text-info:focus{color:#e6e6e6}.text-warning{color:#ffffff}a.text-warning:hover,a.text-warning:focus{color:#e6e6e6}.text-danger{color:#ffffff}a.text-danger:hover,a.text-danger:focus{color:#e6e6e6}.bg-primary{color:#fff;background-color:#2c3e50}a.bg-primary:hover,a.bg-primary:focus{background-color:#1a242f}.bg-success{background-color:#18bc9c}a.bg-success:hover,a.bg-success:focus{background-color:#128f76}.bg-info{background-color:#3498db}a.bg-info:hover,a.bg-info:focus{background-color:#217dbb}.bg-warning{background-color:#f39c12}a.bg-warning:hover,a.bg-warning:focus{background-color:#c87f0a}.bg-danger{background-color:#e74c3c}a.bg-danger:hover,a.bg-danger:focus{background-color:#d62c1a}.page-header{padding-bottom:9.5px;margin:42px 0 21px;border-bottom:1px solid transparent}ul,ol{margin-top:0;margin-bottom:10.5px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:21px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #b4bcc2}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10.5px 21px;margin:0 0 21px;font-size:18.75px;border-left:5px solid #ecf0f1}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#b4bcc2}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #ecf0f1;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:21px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#ffffff;background-color:#333333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;font-weight:bold;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:10px;margin:0 0 10.5px;font-size:14px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#7b8a8b;background-color:#ecf0f1;border:1px solid #cccccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0%}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0%}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0%}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0%}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#b4bcc2;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:21px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ecf0f1}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ecf0f1}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ecf0f1}.table .table{background-color:#ffffff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ecf0f1}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ecf0f1}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#ecf0f1}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#ecf0f1}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#dde4e6}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#18bc9c}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#15a589}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#3498db}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#258cd1}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#f39c12}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#e08e0b}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#e74c3c}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#e43725}.table-responsive{overflow-x:auto;min-height:0.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15.75px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ecf0f1}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:21px;font-size:22.5px;line-height:inherit;color:#2c3e50;border:0;border-bottom:1px solid transparent}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:11px;font-size:15px;line-height:1.42857143;color:#2c3e50}.form-control{display:block;width:100%;height:45px;padding:10px 15px;font-size:15px;line-height:1.42857143;color:#2c3e50;background-color:#ffffff;background-image:none;border:1px solid #dce4ec;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#2c3e50;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(44,62,80,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(44,62,80,0.6)}.form-control::-moz-placeholder{color:#acb6c0;opacity:1}.form-control:-ms-input-placeholder{color:#acb6c0}.form-control::-webkit-input-placeholder{color:#acb6c0}.form-control::-ms-expand{border:0;background-color:transparent}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#ecf0f1;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type="date"].form-control,input[type="time"].form-control,input[type="datetime-local"].form-control,input[type="month"].form-control{line-height:45px}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm,.input-group-sm input[type="date"],.input-group-sm input[type="time"],.input-group-sm input[type="datetime-local"],.input-group-sm input[type="month"]{line-height:35px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg,.input-group-lg input[type="date"],.input-group-lg input[type="time"],.input-group-lg input[type="datetime-local"],.input-group-lg input[type="month"]{line-height:66px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:21px;padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:11px;padding-bottom:11px;margin-bottom:0;min-height:36px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm{height:35px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}select.input-sm{height:35px;line-height:35px}textarea.input-sm,select[multiple].input-sm{height:auto}.form-group-sm .form-control{height:35px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:35px;line-height:35px}.form-group-sm textarea.form-control,.form-group-sm select[multiple].form-control{height:auto}.form-group-sm .form-control-static{height:35px;min-height:34px;padding:7px 9px;font-size:13px;line-height:1.5}.input-lg{height:66px;padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}select.input-lg{height:66px;line-height:66px}textarea.input-lg,select[multiple].input-lg{height:auto}.form-group-lg .form-control{height:66px;padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:66px;line-height:66px}.form-group-lg textarea.form-control,.form-group-lg select[multiple].form-control{height:auto}.form-group-lg .form-control-static{height:66px;min-height:40px;padding:19px 27px;font-size:19px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:56.25px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:45px;height:45px;line-height:45px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback,.input-group-lg+.form-control-feedback,.form-group-lg .form-control+.form-control-feedback{width:66px;height:66px;line-height:66px}.input-sm+.form-control-feedback,.input-group-sm+.form-control-feedback,.form-group-sm .form-control+.form-control-feedback{width:35px;height:35px;line-height:35px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#ffffff}.has-success .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-success .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#18bc9c}.has-success .form-control-feedback{color:#ffffff}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#ffffff}.has-warning .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-warning .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#f39c12}.has-warning .form-control-feedback{color:#ffffff}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#ffffff}.has-error .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-error .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#e74c3c}.has-error .form-control-feedback{color:#ffffff}.has-feedback label~.form-control-feedback{top:26px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#597ea2}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:11px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:32px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:11px}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:19px;font-size:19px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:7px;font-size:13px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:10px 15px;font-size:15px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#ffffff;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#ffffff;background-color:#95a5a6;border-color:#95a5a6}.btn-default:focus,.btn-default.focus{color:#ffffff;background-color:#798d8f;border-color:#566566}.btn-default:hover{color:#ffffff;background-color:#798d8f;border-color:#74898a}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#ffffff;background-color:#798d8f;border-color:#74898a}.btn-default:active:hover,.btn-default.active:hover,.open>.dropdown-toggle.btn-default:hover,.btn-default:active:focus,.btn-default.active:focus,.open>.dropdown-toggle.btn-default:focus,.btn-default:active.focus,.btn-default.active.focus,.open>.dropdown-toggle.btn-default.focus{color:#ffffff;background-color:#687b7c;border-color:#566566}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus{background-color:#95a5a6;border-color:#95a5a6}.btn-default .badge{color:#95a5a6;background-color:#ffffff}.btn-primary{color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.btn-primary:focus,.btn-primary.focus{color:#ffffff;background-color:#1a242f;border-color:#000000}.btn-primary:hover{color:#ffffff;background-color:#1a242f;border-color:#161f29}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#ffffff;background-color:#1a242f;border-color:#161f29}.btn-primary:active:hover,.btn-primary.active:hover,.open>.dropdown-toggle.btn-primary:hover,.btn-primary:active:focus,.btn-primary.active:focus,.open>.dropdown-toggle.btn-primary:focus,.btn-primary:active.focus,.btn-primary.active.focus,.open>.dropdown-toggle.btn-primary.focus{color:#ffffff;background-color:#0d1318;border-color:#000000}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus{background-color:#2c3e50;border-color:#2c3e50}.btn-primary .badge{color:#2c3e50;background-color:#ffffff}.btn-success{color:#ffffff;background-color:#18bc9c;border-color:#18bc9c}.btn-success:focus,.btn-success.focus{color:#ffffff;background-color:#128f76;border-color:#0a4b3e}.btn-success:hover{color:#ffffff;background-color:#128f76;border-color:#11866f}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#ffffff;background-color:#128f76;border-color:#11866f}.btn-success:active:hover,.btn-success.active:hover,.open>.dropdown-toggle.btn-success:hover,.btn-success:active:focus,.btn-success.active:focus,.open>.dropdown-toggle.btn-success:focus,.btn-success:active.focus,.btn-success.active.focus,.open>.dropdown-toggle.btn-success.focus{color:#ffffff;background-color:#0e6f5c;border-color:#0a4b3e}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus{background-color:#18bc9c;border-color:#18bc9c}.btn-success .badge{color:#18bc9c;background-color:#ffffff}.btn-info{color:#ffffff;background-color:#3498db;border-color:#3498db}.btn-info:focus,.btn-info.focus{color:#ffffff;background-color:#217dbb;border-color:#16527a}.btn-info:hover{color:#ffffff;background-color:#217dbb;border-color:#2077b2}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#ffffff;background-color:#217dbb;border-color:#2077b2}.btn-info:active:hover,.btn-info.active:hover,.open>.dropdown-toggle.btn-info:hover,.btn-info:active:focus,.btn-info.active:focus,.open>.dropdown-toggle.btn-info:focus,.btn-info:active.focus,.btn-info.active.focus,.open>.dropdown-toggle.btn-info.focus{color:#ffffff;background-color:#1c699d;border-color:#16527a}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus{background-color:#3498db;border-color:#3498db}.btn-info .badge{color:#3498db;background-color:#ffffff}.btn-warning{color:#ffffff;background-color:#f39c12;border-color:#f39c12}.btn-warning:focus,.btn-warning.focus{color:#ffffff;background-color:#c87f0a;border-color:#7f5006}.btn-warning:hover{color:#ffffff;background-color:#c87f0a;border-color:#be780a}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#ffffff;background-color:#c87f0a;border-color:#be780a}.btn-warning:active:hover,.btn-warning.active:hover,.open>.dropdown-toggle.btn-warning:hover,.btn-warning:active:focus,.btn-warning.active:focus,.open>.dropdown-toggle.btn-warning:focus,.btn-warning:active.focus,.btn-warning.active.focus,.open>.dropdown-toggle.btn-warning.focus{color:#ffffff;background-color:#a66908;border-color:#7f5006}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus{background-color:#f39c12;border-color:#f39c12}.btn-warning .badge{color:#f39c12;background-color:#ffffff}.btn-danger{color:#ffffff;background-color:#e74c3c;border-color:#e74c3c}.btn-danger:focus,.btn-danger.focus{color:#ffffff;background-color:#d62c1a;border-color:#921e12}.btn-danger:hover{color:#ffffff;background-color:#d62c1a;border-color:#cd2a19}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#ffffff;background-color:#d62c1a;border-color:#cd2a19}.btn-danger:active:hover,.btn-danger.active:hover,.open>.dropdown-toggle.btn-danger:hover,.btn-danger:active:focus,.btn-danger.active:focus,.open>.dropdown-toggle.btn-danger:focus,.btn-danger:active.focus,.btn-danger.active.focus,.open>.dropdown-toggle.btn-danger.focus{color:#ffffff;background-color:#b62516;border-color:#921e12}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus{background-color:#e74c3c;border-color:#e74c3c}.btn-danger .badge{color:#e74c3c;background-color:#ffffff}.btn-link{color:#18bc9c;font-weight:normal;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#18bc9c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#b4bcc2;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:13px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height, visibility;-o-transition-property:height, visibility;transition-property:height, visibility;-webkit-transition-duration:0.35s;-o-transition-duration:0.35s;transition-duration:0.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid \9;border-right:4px solid transparent;border-left:4px solid transparent}.dropup,.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:15px;text-align:left;background-color:#ffffff;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);-webkit-background-clip:padding-box;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#7b8a8b;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#ffffff;background-color:#2c3e50}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#2c3e50}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#b4bcc2}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:13px;line-height:1.42857143;color:#b4bcc2;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid \9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn input[type="radio"],[data-toggle="buttons"]>.btn-group>.btn input[type="radio"],[data-toggle="buttons"]>.btn input[type="checkbox"],[data-toggle="buttons"]>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:66px;padding:18px 27px;font-size:19px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:66px;line-height:66px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:35px;padding:6px 9px;font-size:13px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:35px;line-height:35px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:10px 15px;font-size:15px;font-weight:normal;line-height:1;color:#2c3e50;text-align:center;background-color:#ecf0f1;border:1px solid #dce4ec;border-radius:4px}.input-group-addon.input-sm{padding:6px 9px;font-size:13px;border-radius:3px}.input-group-addon.input-lg{padding:18px 27px;font-size:19px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#ecf0f1}.nav>li.disabled>a{color:#b4bcc2}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#b4bcc2;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#ecf0f1;border-color:#18bc9c}.nav .nav-divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ecf0f1}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#ecf0f1 #ecf0f1 #ecf0f1}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#2c3e50;background-color:#ffffff;border:1px solid #ecf0f1;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ecf0f1}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ecf0f1;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#ffffff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#ffffff;background-color:#2c3e50}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ecf0f1}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ecf0f1;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#ffffff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:60px;margin-bottom:21px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:19.5px 15px;font-size:19px;line-height:21px;height:60px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:13px;margin-bottom:13px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:9.75px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:21px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:21px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:19.5px;padding-bottom:19.5px}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:7.5px;margin-bottom:7.5px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:7.5px;margin-bottom:7.5px}.navbar-btn.btn-sm{margin-top:12.5px;margin-bottom:12.5px}.navbar-btn.btn-xs{margin-top:19px;margin-bottom:19px}.navbar-text{margin-top:19.5px;margin-bottom:19.5px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}}@media (min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#2c3e50;border-color:transparent}.navbar-default .navbar-brand{color:#ffffff}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-text{color:#ffffff}.navbar-default .navbar-nav>li>a{color:#ffffff}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#ffffff;background-color:#1a242f}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#1a242f}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#1a242f}.navbar-default .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:transparent}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#1a242f;color:#ffffff}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#18bc9c;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#1a242f}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-default .navbar-link{color:#ffffff}.navbar-default .navbar-link:hover{color:#18bc9c}.navbar-default .btn-link{color:#ffffff}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#18bc9c}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#cccccc}.navbar-inverse{background-color:#18bc9c;border-color:transparent}.navbar-inverse .navbar-brand{color:#ffffff}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-text{color:#ffffff}.navbar-inverse .navbar-nav>li>a{color:#ffffff}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#ffffff;background-color:#15a589}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#128f76}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#128f76}.navbar-inverse .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#149c82}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#15a589;color:#ffffff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#2c3e50;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#15a589}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-inverse .navbar-link{color:#ffffff}.navbar-inverse .navbar-link:hover{color:#2c3e50}.navbar-inverse .btn-link{color:#ffffff}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#2c3e50}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#cccccc}.breadcrumb{padding:8px 15px;margin-bottom:21px;list-style:none;background-color:#ecf0f1;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#cccccc}.breadcrumb>.active{color:#95a5a6}.pagination{display:inline-block;padding-left:0;margin:21px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:10px 15px;line-height:1.42857143;text-decoration:none;color:#ffffff;background-color:#18bc9c;border:1px solid transparent;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{z-index:2;color:#ffffff;background-color:#0f7864;border-color:transparent}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:3;color:#ffffff;background-color:#0f7864;border-color:transparent;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#ecf0f1;background-color:#3be6c4;border-color:transparent;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:18px 27px;font-size:19px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:6px 9px;font-size:13px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:21px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#18bc9c;border:1px solid transparent;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#0f7864}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#ffffff;background-color:#18bc9c;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#ffffff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#ffffff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#95a5a6}.label-default[href]:hover,.label-default[href]:focus{background-color:#798d8f}.label-primary{background-color:#2c3e50}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#1a242f}.label-success{background-color:#18bc9c}.label-success[href]:hover,.label-success[href]:focus{background-color:#128f76}.label-info{background-color:#3498db}.label-info[href]:hover,.label-info[href]:focus{background-color:#217dbb}.label-warning{background-color:#f39c12}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#c87f0a}.label-danger{background-color:#e74c3c}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#d62c1a}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:13px;font-weight:bold;color:#ffffff;line-height:1;vertical-align:middle;white-space:nowrap;text-align:center;background-color:#2c3e50;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge,.btn-group-xs>.btn .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#2c3e50;background-color:#ffffff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#ecf0f1}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:23px;font-weight:200}.jumbotron>hr{border-top-color:#cfd9db}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px;padding-left:15px;padding-right:15px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:68px}}.thumbnail{display:block;padding:4px;margin-bottom:21px;line-height:1.42857143;background-color:#ffffff;border:1px solid #ecf0f1;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#18bc9c}.thumbnail .caption{padding:9px;color:#2c3e50}.alert{padding:15px;margin-bottom:21px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#18bc9c;border-color:#18bc9c;color:#ffffff}.alert-success hr{border-top-color:#15a589}.alert-success .alert-link{color:#e6e6e6}.alert-info{background-color:#3498db;border-color:#3498db;color:#ffffff}.alert-info hr{border-top-color:#258cd1}.alert-info .alert-link{color:#e6e6e6}.alert-warning{background-color:#f39c12;border-color:#f39c12;color:#ffffff}.alert-warning hr{border-top-color:#e08e0b}.alert-warning .alert-link{color:#e6e6e6}.alert-danger{background-color:#e74c3c;border-color:#e74c3c;color:#ffffff}.alert-danger hr{border-top-color:#e43725}.alert-danger .alert-link{color:#e6e6e6}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:21px;margin-bottom:21px;background-color:#ecf0f1;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:13px;line-height:21px;color:#ffffff;text-align:center;background-color:#2c3e50;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#18bc9c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#3498db}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f39c12}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#e74c3c}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#ffffff;border:1px solid #ecf0f1}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333333}a.list-group-item:hover,button.list-group-item:hover,a.list-group-item:focus,button.list-group-item:focus{text-decoration:none;color:#555555;background-color:#ecf0f1}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#ecf0f1;color:#b4bcc2;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#b4bcc2}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#8aa4be}.list-group-item-success{color:#ffffff;background-color:#18bc9c}a.list-group-item-success,button.list-group-item-success{color:#ffffff}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,button.list-group-item-success:hover,a.list-group-item-success:focus,button.list-group-item-success:focus{color:#ffffff;background-color:#15a589}a.list-group-item-success.active,button.list-group-item-success.active,a.list-group-item-success.active:hover,button.list-group-item-success.active:hover,a.list-group-item-success.active:focus,button.list-group-item-success.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-info{color:#ffffff;background-color:#3498db}a.list-group-item-info,button.list-group-item-info{color:#ffffff}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,button.list-group-item-info:hover,a.list-group-item-info:focus,button.list-group-item-info:focus{color:#ffffff;background-color:#258cd1}a.list-group-item-info.active,button.list-group-item-info.active,a.list-group-item-info.active:hover,button.list-group-item-info.active:hover,a.list-group-item-info.active:focus,button.list-group-item-info.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-warning{color:#ffffff;background-color:#f39c12}a.list-group-item-warning,button.list-group-item-warning{color:#ffffff}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,button.list-group-item-warning:hover,a.list-group-item-warning:focus,button.list-group-item-warning:focus{color:#ffffff;background-color:#e08e0b}a.list-group-item-warning.active,button.list-group-item-warning.active,a.list-group-item-warning.active:hover,button.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus,button.list-group-item-warning.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-danger{color:#ffffff;background-color:#e74c3c}a.list-group-item-danger,button.list-group-item-danger{color:#ffffff}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,button.list-group-item-danger:hover,a.list-group-item-danger:focus,button.list-group-item-danger:focus{color:#ffffff;background-color:#e43725}a.list-group-item-danger.active,button.list-group-item-danger.active,a.list-group-item-danger.active:hover,button.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus,button.list-group-item-danger.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:21px;background-color:#ffffff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:17px;color:inherit}.panel-title>a,.panel-title>small,.panel-title>.small,.panel-title>small>a,.panel-title>.small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#ecf0f1;border-top:1px solid #ecf0f1;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-left:15px;padding-right:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ecf0f1}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:21px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ecf0f1}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ecf0f1}.panel-default{border-color:#ecf0f1}.panel-default>.panel-heading{color:#2c3e50;background-color:#ecf0f1;border-color:#ecf0f1}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ecf0f1}.panel-default>.panel-heading .badge{color:#ecf0f1;background-color:#2c3e50}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ecf0f1}.panel-primary{border-color:#2c3e50}.panel-primary>.panel-heading{color:#ffffff;background-color:#2c3e50;border-color:#2c3e50}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#2c3e50}.panel-primary>.panel-heading .badge{color:#2c3e50;background-color:#ffffff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#2c3e50}.panel-success{border-color:#18bc9c}.panel-success>.panel-heading{color:#ffffff;background-color:#18bc9c;border-color:#18bc9c}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#18bc9c}.panel-success>.panel-heading .badge{color:#18bc9c;background-color:#ffffff}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#18bc9c}.panel-info{border-color:#3498db}.panel-info>.panel-heading{color:#ffffff;background-color:#3498db;border-color:#3498db}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#3498db}.panel-info>.panel-heading .badge{color:#3498db;background-color:#ffffff}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#3498db}.panel-warning{border-color:#f39c12}.panel-warning>.panel-heading{color:#ffffff;background-color:#f39c12;border-color:#f39c12}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f39c12}.panel-warning>.panel-heading .badge{color:#f39c12;background-color:#ffffff}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f39c12}.panel-danger{border-color:#e74c3c}.panel-danger>.panel-heading{color:#ffffff;background-color:#e74c3c;border-color:#e74c3c}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#e74c3c}.panel-danger>.panel-heading .badge{color:#e74c3c;background-color:#ffffff}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#e74c3c}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#ecf0f1;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:22.5px;font-weight:bold;line-height:1;color:#000000;text-shadow:none;opacity:0.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);-o-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#ffffff;border:1px solid #999999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);-webkit-background-clip:padding-box;background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:0.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:20px}.modal-footer{padding:20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:13px;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:0.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;background-color:#000000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.top-left .tooltip-arrow{bottom:0;right:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:15px;background-color:#ffffff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:15px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999999;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.next,.carousel-inner>.item.active.right{-webkit-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);left:0}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{-webkit-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:0.5;filter:alpha(opacity=50);font-size:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);background-color:rgba(0,0,0,0)}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-webkit-gradient(linear, left top, right top, from(rgba(0,0,0,0.5)), to(rgba(0,0,0,0.0001)));background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-webkit-gradient(linear, left top, right top, from(rgba(0,0,0,0.0001)), to(rgba(0,0,0,0.5)));background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;margin-top:-10px;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #ffffff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#ffffff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-header:before,.modal-header:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-header:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table !important}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table !important}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table !important}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table !important}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table !important}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}.navbar{border-width:0}.navbar-default .badge{background-color:#fff;color:#2c3e50}.navbar-inverse .badge{background-color:#fff;color:#18bc9c}.navbar-brand{line-height:1}.btn{border-width:2px}.btn:active{-webkit-box-shadow:none;box-shadow:none}.btn-group.open .dropdown-toggle{-webkit-box-shadow:none;box-shadow:none}.text-primary,.text-primary:hover{color:#2c3e50}.text-success,.text-success:hover{color:#18bc9c}.text-danger,.text-danger:hover{color:#e74c3c}.text-warning,.text-warning:hover{color:#f39c12}.text-info,.text-info:hover{color:#3498db}table a:not(.btn),.table a:not(.btn){text-decoration:underline}table .dropdown-menu a,.table .dropdown-menu a{text-decoration:none}table .success,.table .success,table .warning,.table .warning,table .danger,.table .danger,table .info,.table .info{color:#fff}table .success>th>a,.table .success>th>a,table .warning>th>a,.table .warning>th>a,table .danger>th>a,.table .danger>th>a,table .info>th>a,.table .info>th>a,table .success>td>a,.table .success>td>a,table .warning>td>a,.table .warning>td>a,table .danger>td>a,.table .danger>td>a,table .info>td>a,.table .info>td>a,table .success>a,.table .success>a,table .warning>a,.table .warning>a,table .danger>a,.table .danger>a,table .info>a,.table .info>a{color:#fff}table>thead>tr>th,.table>thead>tr>th,table>tbody>tr>th,.table>tbody>tr>th,table>tfoot>tr>th,.table>tfoot>tr>th,table>thead>tr>td,.table>thead>tr>td,table>tbody>tr>td,.table>tbody>tr>td,table>tfoot>tr>td,.table>tfoot>tr>td{border:none}table-bordered>thead>tr>th,.table-bordered>thead>tr>th,table-bordered>tbody>tr>th,.table-bordered>tbody>tr>th,table-bordered>tfoot>tr>th,.table-bordered>tfoot>tr>th,table-bordered>thead>tr>td,.table-bordered>thead>tr>td,table-bordered>tbody>tr>td,.table-bordered>tbody>tr>td,table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ecf0f1}.form-control,input{border-width:2px;-webkit-box-shadow:none;box-shadow:none}.form-control:focus,input:focus{-webkit-box-shadow:none;box-shadow:none}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label,.has-warning .form-control-feedback{color:#f39c12}.has-warning .form-control,.has-warning .form-control:focus{border:2px solid #f39c12}.has-warning .input-group-addon{border-color:#f39c12}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label,.has-error .form-control-feedback{color:#e74c3c}.has-error .form-control,.has-error .form-control:focus{border:2px solid #e74c3c}.has-error .input-group-addon{border-color:#e74c3c}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label,.has-success .form-control-feedback{color:#18bc9c}.has-success .form-control,.has-success .form-control:focus{border:2px solid #18bc9c}.has-success .input-group-addon{border-color:#18bc9c}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{border-color:transparent}.pager a,.pager a:hover{color:#fff}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{background-color:#3be6c4}.close{color:#fff;text-decoration:none;opacity:0.4}.close:hover,.close:focus{color:#fff;opacity:1}.alert .alert-link{color:#fff;text-decoration:underline}.progress{height:10px;-webkit-box-shadow:none;box-shadow:none}.progress .progress-bar{font-size:10px;line-height:10px}.well{-webkit-box-shadow:none;box-shadow:none}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{border-color:#ecf0f1}a.list-group-item-success.active{background-color:#18bc9c}a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{background-color:#15a589}a.list-group-item-warning.active{background-color:#f39c12}a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{background-color:#e08e0b}a.list-group-item-danger.active{background-color:#e74c3c}a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{background-color:#e43725}.panel-default .close{color:#2c3e50}.modal .close{color:#2c3e50}.popover{color:#2c3e50} \ No newline at end of file diff --git a/repo_health/index/static/properties.json b/repo_health/index/static/properties.json index 06fdfd0..330e2e5 100644 --- a/repo_health/index/static/properties.json +++ b/repo_health/index/static/properties.json @@ -1,3 +1,4 @@ { - "RestHost": "localhost:8000" + "RestHost": "localhost:8000", + "PublicPath": "/static/dist/" } diff --git a/repo_health/index/static/webpack.server.js b/repo_health/index/static/webpack.server.js index 0f80d73..0e6dddf 100644 --- a/repo_health/index/static/webpack.server.js +++ b/repo_health/index/static/webpack.server.js @@ -14,7 +14,7 @@ config.watch = true; const compiler = webpack(config); const server = new WebpackDevServer(compiler, { - publicPath: `/${config.output.publicPath}`, + publicPath: `${properties.PublicPath}${config.output.publicPath}`, contentBase: 'dist', hot: true, stats: { diff --git a/repo_health/index/templates/index.html b/repo_health/index/templates/index.html index 7077e71..216fc9c 100644 --- a/repo_health/index/templates/index.html +++ b/repo_health/index/templates/index.html @@ -1,3 +1,5 @@ +{% load static %} + @@ -13,6 +15,6 @@

Repo Health Assessment

- - + + From 41a8a76f2c91918fd055b362e8a5e4a276d25a54 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Fri, 24 Feb 2017 17:43:29 -0600 Subject: [PATCH 27/99] Fixed tests to work with webpack --- .../index/static/client/karma-test-runner.js | 19 ++++ .../src/components/search/search.module.js | 3 +- .../src/components/search/search.spec.js | 2 +- .../index/static/client/src/main.module.js | 21 +++-- repo_health/index/static/karma.conf.js | 89 ++++++------------- repo_health/index/static/package.json | 1 + 6 files changed, 62 insertions(+), 73 deletions(-) create mode 100644 repo_health/index/static/client/karma-test-runner.js diff --git a/repo_health/index/static/client/karma-test-runner.js b/repo_health/index/static/client/karma-test-runner.js new file mode 100644 index 0000000..82c5c11 --- /dev/null +++ b/repo_health/index/static/client/karma-test-runner.js @@ -0,0 +1,19 @@ +/* +* karma-test-runner.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the entry point for all of our tests. +*/ + +import 'angular'; +import 'angular-mocks'; + +import 'main.module'; + +var context = require.context('./src', true, /\.spec\.js?$/); +context.keys().forEach(context); \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/search/search.module.js b/repo_health/index/static/client/src/components/search/search.module.js index eab6046..66a81a8 100644 --- a/repo_health/index/static/client/src/components/search/search.module.js +++ b/repo_health/index/static/client/src/components/search/search.module.js @@ -10,10 +10,11 @@ * This is the module definition for the search component */ +import uiRouter from 'angular-ui-router'; import searchComponent from './search.component'; const components = angular - .module('components.search', []) + .module('components.search', [uiRouter]) .component('search', searchComponent) .config($stateProvider => { 'ngInject'; diff --git a/repo_health/index/static/client/src/components/search/search.spec.js b/repo_health/index/static/client/src/components/search/search.spec.js index 1ce7ec0..75db1b0 100644 --- a/repo_health/index/static/client/src/components/search/search.spec.js +++ b/repo_health/index/static/client/src/components/search/search.spec.js @@ -11,7 +11,7 @@ */ describe('Search', () => { - beforeEach(module('components.search')); + beforeEach(angular.mock.module('components.search')); describe('SearchController', () => { let $componentController; diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index 92fdbeb..327d744 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -1,5 +1,5 @@ /* -* app.js - (C) Copyright - 2017 +* main.module.js - (C) Copyright - 2017 * This software is copyrighted to contributors listed in CONTRIBUTIONS.md. * * SPDX-License-Identifier: MIT @@ -18,11 +18,14 @@ import components from 'components/components.module.js'; //Styles import 'global.css'; -angular.module('repo-health', [ - uiRouter, - components -]) -.config((function($locationProvider, $urlRouterProvider) { - $locationProvider.hashPrefix(''); - $urlRouterProvider.otherwise('/search'); -})); +export const main = angular.module('repo-health', [ + uiRouter, + components + ]) + .config(($locationProvider, $urlRouterProvider) => { + 'ngInject'; + + $locationProvider.hashPrefix(''); + $urlRouterProvider.otherwise('/search'); + }) + .name; diff --git a/repo_health/index/static/karma.conf.js b/repo_health/index/static/karma.conf.js index 5d590e6..c88dcd6 100644 --- a/repo_health/index/static/karma.conf.js +++ b/repo_health/index/static/karma.conf.js @@ -1,80 +1,45 @@ -module.exports = function(config) { +const webpack = require('webpack'); +const webpackConfig = require('./webpack.config'); + +const testWebpackConfig = Object.assign({}, webpackConfig, { + watch: true, + plugins: [ + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + 'window.jQuery': 'jquery' + }) + ] +}); + +module.exports = (config) => { config.set({ - - // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', - - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['jasmine'], - - - // list of files / patterns to load in the browser + webpack: testWebpackConfig, + webpackMiddleware: { + noInfo: true + }, files: [ - 'node_modules/angular/angular.js', - 'node_modules/angular-ui-router/release/angular-ui-router.js', - 'node_modules/angular-mocks/angular-mocks.js', - 'src/app.js', - 'src/**/*.module.js', - 'src/**/*.service.js', - 'src/**/*.controller.js', - 'src/**/*.component.js', - 'src/**/*.spec.js', + './client/karma-test-runner.js', ], - - - // list of files to exclude exclude: [ ], - - plugins: [ require('karma-jasmine'), - require('karma-chrome-launcher') + require('karma-chrome-launcher'), + require('karma-webpack') ], - - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { + './client/karma-test-runner.js': ['webpack'] }, - - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter reporters: ['progress'], - - - // web server port port: 9876, - - - // enable / disable colors in the output (reporters and logs) colors: true, - - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, - - - // enable / disable watching file and executing tests whenever any file changes autoWatch: true, - - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher browsers: ['Chrome'], - - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: false, - - // Concurrency level - // how many browser should be started simultaneous - concurrency: Infinity - }) -} + singleRun: true, + concurrency: Infinity, + }); +}; \ No newline at end of file diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index 5e3cf05..f68b797 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -29,6 +29,7 @@ "karma": "^1.5.0", "karma-chrome-launcher": "^2.0.0", "karma-jasmine": "^1.1.0", + "karma-webpack": "^2.0.2", "progress-bar-webpack-plugin": "^1.9.3", "style-loader": "^0.13.1", "url-loader": "^0.5.7", From 21bc34d1dfcb59050cbd260e551cb71e8095e8fc Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Fri, 24 Feb 2017 17:49:03 -0600 Subject: [PATCH 28/99] Added simple dist script --- repo_health/index/static/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index f68b797..d693d41 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -40,6 +40,7 @@ "scripts": { "prestart": "npm prune && npm install", "start": "node webpack.server.js", + "dist": "node ./node_modules/webpack/bin/webpack --env prod -p --config webpack.config.js", "test": "./node_modules/karma/bin/karma start" } } From 0b6906609921ab5208ed02fb7a35c5546154cf40 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 15 Feb 2017 13:38:26 -0600 Subject: [PATCH 29/99] Some typo fixes. --- README.md | 2 +- docs/metrics/PullRequests.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f4aa5cd..4995e63 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Assumptions made about production: ##License and Copyright All source code is covered by the MIT license. This license is located in the LICENSE.txt file at the root of the project. -All other material, such as documentation, is covered by the Creative Commons - Attribution, or the CC B,Y license. +All other material, such as documentation, is covered by the Creative Commons - Attribution, or the CC BY license. ##Contributing External contributions are not being accepted at this time. For existing contributors, please use the following header documentation at the top of each file: diff --git a/docs/metrics/PullRequests.md b/docs/metrics/PullRequests.md index 9b1747c..74bcc34 100644 --- a/docs/metrics/PullRequests.md +++ b/docs/metrics/PullRequests.md @@ -16,6 +16,6 @@ - most contributing user (user with most accepted prs) - avg size of pr? - not maintainer pr past year? - - not orn member pr? past year? + - not org member pr? past year? - avg comments per pr From b65eabf79c343a9db13628d5636b17110ee00052 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 19 Feb 2017 18:16:04 -0600 Subject: [PATCH 30/99] Update client-server workflow with current pr url. --- docs/Client - Server Workflow.pdf | Bin 23658 -> 22220 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/Client - Server Workflow.pdf b/docs/Client - Server Workflow.pdf index a8b119689554cb60a4bac050d61bd88832f0ad05..f1e413aa1b19f38915340e22c643d6348180bb22 100644 GIT binary patch delta 14455 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ėeFEHjXaZ0h@loy$wXnvSf=B9&Mk<^nPTz=naY3SN>%Xz%YH+C5?AY zqY~Se|BQU%Ivp7Z4Sq7tI$Eto3p3x4MVE3cg3?Or*-WR`I2$U-Gs-)tSv)k6lDy%k z66luHZfTDEH&VW$)AXu&tJ2!!SXg7+?;UyU3xSF{h$SIAYNZTHzGb z7@_a0OGO+F(x2mQl#l+j`Z3^Y--({k!FK*`FvKh0)2qrNAgT$oM!KwzGW5VZdM%3ix?X_t4dn;Sl}n+l;BCk# zlU)vEEWTy%SES&3dYFnr6um^$+Su**c)l8tN)(NGH@wP3)8No>O?ycKMNR3X@-CWt zBUdBv#z7Yxl-7k5kas#m8loCI^aWm=;;z(?k~!W8be9dBN4&uw-(+_+pPL~>WCTXkuH-9y5g~3i9yWG96K+yr1k(Ro1WEq~WQg#8 bPe3Lv|J@u~SR$~q@$hgVP*F)LOCkI}4Jd2h delta 15882 zcmZXbb8ukKw(n!x*2K1Lb7ChG+s=+{W1@+jOl;eBCbsQ)zjN+;x86Os|LDEy+pBhW z?W*3Z*Jo8vR)e0kf+jQrY|P9of`V`^uFhu0c5t3QFa0Kx&iRwJzW}&y;jux&RX&sc ziCk^ZEw!sB?UV~khoi^X548NUibAqpG%s?NLNeI|=^$aUM2{a8#*=^p?O%8qZk9^+>)SQ@wx2Ke`{>Uv;it?wXzIy!=Iw9oFfxjEHot&N6D} z*zbW&8Ne(I=*XfFSbPyQTe>ml@B9AV$!)J}O|Xd~??3f!)Nd5_v7Zh1;z;?o%=Rl6 zfJqee`x0~xW(080$dUV~y)6k;_hz0+mAM2FNPS?jECSBkz2+PQ)p zWj31r-%iSu@x$IE*(kwqnry}CkV(N~-zJy{*oDha{7x{LC8F)8!6#adb~_JYvGY5T zd%`v`r`}@1Sb|Fxhe_|G{2NMIaB|xe5D*Z!4|#r+EdVaKFvWS#*P7F=RX=HOM&+z#eg^}l0e@zh!GI>IA=$B@4E6F{GRQBaHrbKe4G^j;8LS)Af zX{e|ub<(HymfAnGef>Y@@kPR|HMi(Zz*oBdctEi*c;QE4iVf{p$vKJ+<7V2eC3rC5wd z!=ukJa=II4Kem%oUY?%ISxlx25{`Hk_O0n0X1Ns58GUeDj6F(*BBfUNQ3!FK@|mcF z^Jd8pBvl*2=G(uDL1GW)CJBP$ff6EGbA5*UJ3AKTf zngZGx$YTxznY$XB2DlUNXAecBGUkoTmzAYG>sp7K-pO}Nhw79BP2@VQY3ee-)2w~xf6`_$C0L6T=!0Nn$Cw;XF}?oz%-i4z;W*WR0qols%>&fYrXeV@q9U@Om7(P*REBM(~4pYA=a(T3-wCZ zNX{NA{ifmd@daIB=IRa55)yoEk}gnF*qHfDLhvQ}0?x|`{_or4lDDc2cNvK^Vw~`L zt1VuhaZVB3fX(*GVlm+jR=>zm>$LJsKl4zP zg4aowF=}|#S-!q_D1nLtCO8*Im;@_yz%R0+0Jj4Dg8Xk4EPr>bl#*yKBdf$pmj_#6 zCLze!$;@RHa*QS4zg<^!2H%(~IEMbt)=PGbf?bi}#Pt!DhFY_J zE*g%Wh4iyWB)V+EU`+R>(VD6&5H;$}!^wUlAZ@oX3Pt2@B|qb7w$_T|bu8iVEXTc& zbF$8o?3IoNf}KS^6)!6@xS9-Z5vm!soYbbV?uBZ;kO1PzM)=r+MRyS#h56T!Mi7smW2$Q!KsEUWM%*mg;ROF5Hv$-L$ zW8@o zR zNs{>;RW4W};)GHMCO)NUdASP*yM!u1EiOWJ@Qs8CYXF=MLY$tFHVh3$*$B>qao|q8 z60J5J4DK!@!dN*5VYrH>L@^zzgRu;=PjqjQD(IMf6VHNP&;;HkFR_EAo|o|ch{PQ& z`UTt&)^@6q7E9Fk)N*XUhPM-;w&xy5Jp~CL3=~u)u!Pd*TNz?&B%I+uf9ms@H;tDv<#202&ebrN8QgW@_QIFF{>jTv~dYeo#fAeBgL%MyncK zMJu%vVTY#0P3%U;-K$elMoBpvQ;3a9oH7kto2==yus-&oTop8qFXKV>{p;Dnv zeDK~Em6}yI}-hfxtYQvLOSy z99Pi9^y-Jm!RpXlV1d&I!%!~iJ-HX08UVS8bx44%D-X z*buD#g*vl%UrSlL;X-Rf^d-)KBS_Uv-}1C$GDQnXsE7V%gDnfHxQCbJEue(HFVT10{|R zZ5zQLbM|XYNRd0_PNsXnRw-VB9Z&$n>C*e!Si>8qJY~Z@jKob8Y<*T=c#}jxZjTr| zuXCo|6i{Azv2woA>ni0{TR2;~n&_pXWmt$wSNT#}6%7ni@TE0SDM{UaHpd~9EBjj3 z_I#&KgBwyU(4xigSZ{i&RrWwVJu7(6?%NTlG7 zom(s=^VJeLRYO?Cbeg@?ObD_;RKC!>rQCBXt>;r6!2qv)HY*r+40AEhBE$LM^CO6m zZ-@GpHwU=om244vrpOGc|E+NSTfq;SAfA*vd)2^SH-!mI>#R)EAA#WaI7jdS<9Pbg zCDY)+Ncl@dP-+puK&fp?zK^M$Y8VZdUu21BCUGHgPBjCcf&J3N$W9ed&-=VQ6nBQ% zpK9OF;@Ybs4_jRlQq^4}He(w4mwO4Rgdx?&VjUQ{z3Emxw>#G(FF=fu{Digp=>W~z zA1RgyO8X}+HS^t-0%x#XP#Y6!uPMeck-*#;^zw$HF`~e0P$(hUo+x{QoPD*}v5>1; zNo6l~@RaISa)#<&x-)SQU*^BN$P?0ANi+x7LC?bP(`q@<7}+&Tu7*plGg>(Shy6c> zAoYYr!zit=&r7u`{TQ&kM8TEv{wYZr@8=xc*$sp#u%?D10X#3vOD{MEI=qZDU zesKae$Ri!mXsMxF$IJ#>yT;Rg+81$8^O^bciY;pXr*S{57{C`1If|?TB~bD939SFEgprL4eKdkf=7Tcu*SVb%Ms^74jYdaapMCH1xU+d277gT{Pd zG$B{~Xj}D{bk8?X(lU@j7SxxstDK-3u9wp{-s1=IZy>Xw&6FvJ8Kl*bva?7yTBUQg z{vNLU2^i;{nZ`hSz7J)+E!xtZ+#hbn1x3$g?-~lZ(5VKkflpuVHNw_Bm@%Rq zGiGw7_`2&;&2ibB@~!Kusb~xm0dB&g^4VOtGtEg( z>*1XIygm*>d(>gSo5Fs(Du_vH+%fP=WF`OwJ7;)6TKgISdSNpK|tkOIpZo!dfGtua%S3&3%PetPHs8JUYn%) zhd^PqKgl$abajM?Ikm+HNe*dp9&6X1{`0iTIkQ0i=bjUrMJk=fYMYK^q>=XoX(qkq zlw2%p;FJrMwr+rB8 z)+Mz;=GQ0FKvC@;W93UDJ#;D2-zP}keU)XetDnHSmZJHCWN4?c>|)x4$-PRy6B-zN zlaUx15crAmPgJ$68TUPZQ(@YXUidwh+_0s&K|*63VxM)lX1Y2_Fbk1TI!0g8u*#k? z7E{^?jz-k`cOKo9ocx)S4vTpkJf@p4#za8hO5hSE0rmT5*g$MhW%ho>nURvsLBxT3 z;y2*MlZ6=FNDO4r=%*hIrCr+oHe*R|Ib;Fq@ARx`@Dw~T%cMkt6%KDR{dXE zXc8KGG}cPPo4hlCJk8y+%hNN^A$$-HPmJnma#+x5ci~S$Yp#|HmHK{r#jsnM08?gG zxtJlU()EpW?luyG<$mje0)tr`!cBGqF$<8~#anPr^00?W$axdteh8A9ANQ3Xmr7)j z*es+yWH3cl{m{Jq-A>Wn5b{<_1Wg~Q2He}44@t91#GwP;TL_xMs+N(2{s=$h5@esn zxzl|pQ2&S6n6@idYFsf6EZiPGU;l?faT91@Z$`Q)SRq+Er%Q( z`=2y?rk^j)j7srW?N%3yi%m?8Sc@I0qL1~hjh6xQYA32STNX@DCkz*J^#XGdo`T_0 zcfL;t5sA_?t9G0U6=H&>9pLGj-21>ZJ?wd}_ClLC`;bpcyfdl#7vG>4xGk?@Rd$m7 zO!nl^++x$aPlMAsQPhAd8g(X95i`0xyD(gt1V*TIl)22oXG;Gucx=brCx$XrA>+JdOrEzp2Xl(d{o!aEDR8td`NDsb`=S@8E3C1RBV83NZ&=r zx2ScdL-5XgzyjoWkV)J>Kexi91S+*iqxE538N5_1jj`@qn5^l<&fI9UabzNnL6XN2 z%_~%MZ}OjZ`aXtCM?tFy$rP-l=Ca+H`AZnwpiz>T`&~BXCc9i$%je5YwZM#pP~cM{ zR2#jZL4EUWCoR-wNwM1SbsO(5&j&G{+z#Wto{T8H$AR%z%in^(EMFD`m&xH6!~kZ- z=s+#$kQ$v_5lVmQGLvxZ*Eqj7aq|FRmK8?-NTne2N0E|gt>^E?4Y47E15#A)_2}l$ zSkzFitjH483gxNwcI-6>mTzDFN3Nves3-+e_N2@%)}3rE%V`{+T7rG#gz#agHMr&< zo?uY1n`C}C?;&@&5ZgRnTwXAAyuh7Wq zO|O>hEd|CwdOm=S-MBIzgK-kwJphw!4_xG7)su*$oXRjsQ!Tnq5dE+9JAK}@e1I|H zQYdc8FYUReXu2pF^LpO2+s9E-!m2mVkoHp13Y0U>fgeh9YsdKuY{~H0M!;O|gP?3= z$l5irc~2k_dG0Z>SMG|ri4Y^pg-rWbXWJB>8|2)?3UvRYS<)-0S}eI;?&cH063CX7 zluK(01c&tt1ktFPGXT@xqQ)Slh z&_v8~zdh>)pl8o^qw4)A(8|AIc!_1Xvp^admeT~7S*M;)SR@!9W$L6Le4!zlmT*lb z3*iU?ypW0M;s$75R%W&$<9qW&*_J)Q$tE0EKX3#DBb7b-GrNK@wri!)n8jCvP5NRd zdXF>B62+yO^DWl}y&l-9Xh&3R@iREif?1~OK~AJtJnAw;wY8y?Yau-FV-QxDJt`ms z&p}mbu?fn_kZ7Z3XQNADx+7(x`W#gBO$z@IhFfJ37dvMR7eFM$n2cw_CCjssw3U+2 zx6#V)9VO%9k^pL(GR@6sY*%*T_d;P6mMt22MFBTC+$@R&{N0{BdIWnj&Btx$(*9UFpl9C&tvD$(5r zG%ZQWdj8%EeAS|K{+$6{dd_D;p^~bHz%XRu^cX;9kfN7o>Cj>tW00WOI|*k00e{6`;6G@< z{!EEeVy+Fpw|hx8)8KyHI4bmyrih5A)s}I4X_CV!hRD1tqs5|qgZ`sdr~Zoo6bc4B zO$6k7OK9^qin0i2yQ6u{>EG*#Y$EkV()cC>rd+P6dF5v^1P?K&C{A4 zfybuLaK$`YGfM~YcmO(T3u6SqMT8%{MV1s!f)C5Ci1lUTrxC0+WtA706ci{FV97IrU zFtbvpPElVnlaVh^)z(!J-z*fsXajGCQJyYQwr|<((og?dDdL7bp^=fb1HV;5pTM(z zbqH2mReXPEm6dH}Qg!FM$&I8n7xC10JKC4D`C(1Flx~M6a8%EcMv?X`iOH)yAX=KQJQgm<Qjw(}W)r2im)ZPTp4xk$ePGp($owY0${@;Z z9lfL&u6_Kt5|^jY_(SkHF}tw+^$8R1zTKZY(?l zYR5C+6tBOEn&3;aKg4C*L};KyP!9NfbsztnVVg}fic6=s<}2}?M0@yii`zt@Y2msR zS{)5<3}E-$b)La6X$NbZVQ8Cd;#EdK@fcy=B^dGO6$HNBY1deG^U)clE6r^3q}?A6 zu2@q;w0E-K=b8nb>2+nspaba|r*L+zhT-9>un1x*Ft$CRfvykYEfx?EI$d^@p$)Bb~| zLzoMQMw~qy1-72zvVwKIoWJ{0^19keHu93Vc&+9KDBSNq>c3Wx@Ak10ewk2!J28t06Sd==z$DHzs~fc9tqevNgQ8)$~+vr)`JDjXdW6xB{)9mwFo zaE9EW!aNfe`x#cHJx7U)X&%dNrj++C%Q4%^&2+;zy)DV+km{uDb8t(qs1 zMLU?t0=1;vfh}4y^{ZYa7g=j6-&}aCL(I49;ry5K;VjLiVhM;joU7=n1gs&dWzu8l zP3cp@lrAABKH~3Dsnlq#OuQzw(2gyg$$pII|2Ha`R(4`jk`Hb_ILyp%I!U)fHcS98 zSARgNdgD$s;EFXws{FujP1*o;M_C)r(4Sm%k#c^ACmznZ_IuCB8^|Fp>kVwZ56^4A zSA!-PYTUA3Z?>lJCX&l4Us~5L!{hT)P#-Kr%&u9e@)L$hXwdE}mevj75@dmSdlauX0K*^l0wPdtz zt1DOtKeyB5h~PfE+8NkdkrsfOaU;TY2-IpQ|1>B2d*o_Gky8Kbeg6Bb>=r$HQ$1g_g>5&WDmNjsW366#3>X&WAZl5?3B#GF?m@b9)`0eec2i@kcyxVXZ=oNN!|aU z3FpnFNHxByk8=dKF1*~`dE#z!-WTfiswoJKZD>t{#oayo|_O0nAW_E6wlTe_L3h`H zvmPzNGEiWMju|&KQ3HJ2;A%4F3AF@Wi;6m&Q!r2Z=XB8aig%NeYge$D%?U+=^A0tmX7a!shD}M}dob*+S-Euq~ndG|W zxWG&80?E60Y#$9{p_VH1v}*JAZZptNJ|uGZU2p3CC70hiF%E#(@t7lOgTuhwDD3+T ziPL4c<;v@ z;9$M=wJrWqdtm^o;Ec%dMh?HL+H>f-Uf0JYH@Cla6TO7N(+NGMoG^y2j5}wR)O2w8 z(Killc#bHDCXKwm+ubvglY>8nlOki=g6*>R!E|8b|4m-1BN6ds zOy37*k}TB;UXIH3`ec76_3V8b#~U(&^3A(SY46C|&BYC;u=%kDYQbI{P30m{yneCX z`7wm<(4RCvn7XHof(h-BlqWEVrYBBEUz3bKr&tZR6pqxN?yWcwumN%Txxz(80=_k#l z39;~$nfV2?o|6@5jj#NwvfwymK6DVoUMJ|C1fnB&^@AIFdRw{8^QK+`rBBMl%9C+a zmLE3pQHgc4APpMSrqzfe_ZSt`>%p6Je|=n@v>?!?$zCBX*!FHIkfc--KkzMY6N$h; zmI8SrMb>`Uy?#j`se1aUia;01(wzmvX=!9WfYRG++l~z(oISD|R+wE)KCB|;H5l9N zVBIf@tJJPe_64al(y<}iC}z*+Z4!}>wXB*&^|Te4&lhb?%$D7Us-iA1Yac+&ZNG$^!(Vm}p9_$Yy2!sr!TV*g+{X{d^wo0g)ydvl zB~Sfvux4Zf?L)SD)8{#47@*kdWi27;I@1@33q3B?1yZH84SJDS0anz^E&fn4b_|3V zHzdVTBDpIjqv|f!RWh9Mbj}e{K`q;A)s8+g$yQL8|0;?~^6qLwMM)9)?YDMlK{AMj z<%*q>ipQxsaKvG=>e++dhLJt_ZS99QfBHxrO9oQq#DMvM<7HTqOp>6c4DXZNe2p}; zA;sx0kPv)0;XgEay_(#5%abVq9hpGvd{Jxbd^;SfrIeX&4*V{QPIGY;8T z3dM20y2x~eCoE;l+M8^s3wnfmLMEQHbfZ)eTdpw~J+u4nFSS(=r}FzpfB$~|3HwW( zqjji69u?p|MND*t$&nlJ`uA6#?`b*0WW{LLiJGtw4k~W5&>6Oi>`96P0eH8$pD{W5 zwb{$~o!o%T{?lD5;>@48T{v<;-0ZZM=9y=iNrA-JQ!+HXjmr0x+K_doAA3`yn_k%B zXRPFXN)V*h`HE$_cY&ANVEZk zzBJKZtMNP=sH^Zw$?ndDll7O$nRgT^TVnE*tw-3a(1{xOm-fy?NR0SpGOXrK-W#9c zqg0P`GSz2!u$3(~bTUwAzv;jr=fWkRT`^o&odYLwsO?Sal|n8Rl}be<^-9D}{{7Ne z2G97@m=A8unmiyQ(F;X}a6Jv{_}BYT*d2%*N66U+edYinkY+CxQT}5~#8P;tl!Q<; zK(w~F^nGc^`(bdp6GyNZSq#Zq6S!??G+Vpcs(~Ya42Qh*kpP(NdLMO7Ib%h_#O(s%e*gy@RN6V&BEtS+{Cx|qUw{5)awlDn33BOaZ`?dUyR zf88;I2D;BYhK7xK)v}%zLzb6e`VEab37ctCoOZRT=A4cOe1ZHo5C$%j0x1GyERcDG zr|&=1tJU=h2Ux{RIK{`9&F{OgQQug%;`9FhZ!+sO4yu!j4FEga1~kdRa_Jv;|W- zdQ4&73QJG|P9W;~&k?9;z$q4TYb|+eVA~yq$*p5Uk(^BxhWBTm^UGc$lA%`LgCJoM z_(Hr09pBma8e`iq6Couh)8?mSM>-9Fnbyd*DuHN&eQBZiU*SuUek}H4Z4AfeUKYA6nP1MS5$PMMm)=% zyGDgfD%J#b13qem<3$d1Qs@+A48o5X0b7#M9E~OULxgQi#1_@x?1@37$|hCPbV2-F zoJG1OjeR^x@|E#~)+(iE5JVc!Os4Py!YU=c9{-(QiwQUoou`(=JFIrsk%CzqK1B`A zqF^p!qA)dfY7Zf#k%^oSq+Q!xcK9j zrHHNj!Q@H03zIimCB5cSD7lV$9NFBb`+ zlFPAvP}fzYo<}*TLstUUq)q1mEJ*%kZBM_d#x(Q&P3%b9kgoY@3RVETwXSXeE%T5k z6Lzpi0JPY%Jqxsh zkr9@+6w-ZobLU+_iUp($wXU<+is2JigQUrGOJU-bsQ77@x?LMC`Pz2ul>@!IN@K!? zn>XaUmUEF@FY^tF=h(@32y_u_1q^md>t5EM_91PWs}`slM$#~ww1POuwf5VBI1mo5 zrz){!Mhz-;J?-MwO(Q{UDn$t3WeJCfa>bP41V*%x%Y-`w0aO6{(*FfXJQJb`sw_}Tu7!|yq?8km)y^(#v+fBJI2 zyzkD=Zl~1!{O;ezv(6sc1i$Z=zKDIal-!kMj-C|&oS&C7T(vbsewMX%#3%N-hFt>V zQwx>PL|uU2{o%&oCE2aT#Gt#^i38~w_QYZn?z(8rA9{4;=s_$Kygl%N{m1oLIZt13 z#7_#aM>fk7Dwt&&u+MGkzYdI@NdhVA$WR3MAk!!J)_PGe3aHMacuL#gD0l>*ZUaVQWha z1_=nLZOW-nzT{{|>=q*KHe_VG#EujSb0z~Ov-0UtgS}b52d0M5VxQW7TvmWsNefTL zIysUD;&6wFa_9c@XC@{+n|Vw!Qe+W}G--ElEJKUW&lm`G%+~q=@t{Dy(R)`H0m@+5 zrbiK}6mY!2<+Nk$$S>uaYXT9#S_NwfiV5zz5#Gm>|EJ!1$a(w+Wf{7bOW9x7;3XMg zqlC?051i}i&FFl2u~bQT%dLdZ|AY4oh~J!vxHPi;69+6OWU6tMv?w@SD+ACfe_>Qi zfBN=_>O=Qx9395IX<2fcbZO8|kt~bjC*SH?UO14P)ndN-a~30vT@|mPqg#IDZs&Hp zx&}0zmejVhuE;-D)Ao`{FY-k1^LP z%AgPO@ctRqqDVNp$)8xF?<&-P2WKh2;iG=biRa+DW@2%+I*^OmEY1#kd&+R>T~0wE zO6Ul&#iRQ)7C}Zs9l!%SKzkr^o|UVY4WlJHaZ5eb^C7dT#6tG|t8d;z$8`gIuF76i ziC2+-Z+pBP&tAqRsn-6ZfsoiE8iq7<6M`A+dOn^o{5F6?5XGmJ4|xV8+@Rv~*9bFo zsKkU+n*oTunTTc_$uM1C@2poPSY#oF5m#C zTltL555W?I<~;g~;i3m8NGb$C8e;z?h9zcaDbTP^V6K;zIr&Cc6p|Gy8H0CklVv(0 z=ns)T7hC%-x@E**I;w#Q?g&#Z;|tZ*+(arHd-B=}GbZIAG~`AfCemgY!-iUotF;E7 z%0**-SN#JJJ;z)z#Q;B(Z;tQFCPL6P;7xv0?Rt^iJrTVD2Zk|63EisbrV@2NiBagG%j%(>uYh+|A$wX}A>l2PcDN{|~XfThCC79?O#2^zwI~ zRmGPDxW~H^8FM~kMyeK3B8Wzpp?pPa%U@AhbEo~;9)IiEey}b9LTesL25@--TYeeo z1nwEWt7#gR;Pqs)8N-Dek)vqdPHvNWJYAhyM{OKb(FTYfJgWjyi$SktuzaKf!TLft zT(0}XXdN>c!DwO7&6&hmOrU2FSo?y$WHwpLjns?8)j#0XSJMOwzt|4S2E^t0Ww9Fe z0b=1@@(_N+qd|56nb;S_#1$hCWJV`%vXI!VUFu%?A14=zi>x0+F(FK-Lb2sH@DVyJ zMi52l8W8i-UJJxR;F0V{ODwQ?sw#{!gF7rGle?pMp(B~RB_IZ9d6~`K@PfOu>&pn# zo*7<7CC}DFr#vp?_8Rc`qu=H49K)@7Bv2iX11%8c*DFm)f-;_ zXyp{o6#66U;);FMxTKp&LQ%9lP=^==iK9TXGn7RpDp2%j7tq}-dk%Bwg>+|$EhUZd zLX|X3wK1BKZi5mc>pec9{pR27`% zKTKGz$KZfR=g334A+$}X$h=tymBi-eib)#Ox*{?FnFj5C3x}ieEl`6xL&SI(Zb_S@ zCKDbEX`Vy_{&Ygfd>DSCh|FnWAF@e_Bv`HLpj*Y2K>pG|lrB+1Pvqt_#T>&$&@zp> zL@8^UpZBQc@mJQSy*A!)2zu<{{a});76Rp{Td#QTVRPKrx=$U^k~RJ zh=IYN&li+W`PYWz9^B=Do$*PeIkebmuyauC*-E%Eo<>Mcv?7*?Y{lK5EPr>U*U<_G z|Fs%3Xp(f)-ZwagKbK@=M(+I*YH3yIV`z9)p@sMAtSQkq>)iq`3>Ur{5aHpnFn4JE z&po(B3x5tV=c#!%ws3R01qCXCx81${bjj|Q7yUQSq4$Wo1w@>tZR1fnanDgyQXc2i zk(D&aO#JMhBxF1yq(^AjOEQ=VnndohD{vSDR6I<`;#;RDI%-YvFr-*|#wgKN3;u zYML<|!Alt-$ad=7h>_>tcdw3`JcOL&_T)|*8n#Kd^`rw!y$F*`*1(**Ce^vXv;a|t zkz^2sNFC;Zfw}=Q)bt~YSKNnT@_HBn`i}XBgtzn+*gBlQq^xKD9~!McKCV_+{wR7= zD6jdqGYsI0iT$|<5r!bBIosO^!649Doj)fr@yCM`kJ3!C-nN$38-mdIo^;8a#^vht zD5Fi}&NYigkxGubpAlzoH{ShT!U`Y_?W?NNB&kTI>vBjlkWgS6=8I3^_jb>VWicvx z;+^h;r&25&-Z`%5n>)9S63zoOF17xkud9Slfec9yq@{{#{TVTp611JjLJeOa z7@IvZk0LkSiF(%Tf3@d z?H(1zkfTUQ4(biQaOKiG7y(iQ&SF&B@YxWqWxv<_%?RE}M5|}Qbn?J8F@%t|lLO_s zPip`Pa85SuJpYyb18Ig@un?m7pL{Bu{8Rqr0#Dm|)n&)3h77~URja*X^-FCN6el`H zWh5q&+oMyta8Mj0-MBso-K$94HcJ%M13NiM9D}4ABVi(1PQunRO4#c-H;@sp_xb zNIkGcYPb+04(T$v6lhkPY3ODzO}5P2Ur-m>Th4=u$9~G+7XVoR=n&H&rtk zQW$NI?3!YcbM)l9z5{$8+T9`A*&Oe;4wcJt7)(S>lF*z#ibY8|Fp(+hqtY=QYqX3e zPKQ0}*Lng$?duOEBL=6&N|b0~8U_omyysxYS?ji zNZ$mA#>lCDsL>wS^9P%3QU2OWDbV*yENOeY6ZYo$mgPlvD-67eoOza*l;FAeF0k0j zRz`&F8)`(R3l}r%{~Jr5`)-26$(>_+CT4Q|4% Date: Sun, 19 Feb 2017 19:15:17 -0600 Subject: [PATCH 31/99] Stub out pull requests url. --- repo_health/gh_projects/tests.py | 6 ++++++ repo_health/gh_projects/views.py | 20 +++++++++++++++++-- .../gh_pull_requests/models/GhPullRequest.py | 14 ++++++++++--- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 70b45b7..b1c7ad3 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -60,6 +60,8 @@ class GhProjectApiTest(APITestCase): project = None def setUp(self): self.project = GhProject.objects.last() + #Django has a lot of pull requests + self.django = GhProject.objects.get(name='django', owner__login='django') def test_api_get_project(self): r = self.client.get('/api/v1/gh-projects', {'owner__login':self.project.owner.login, 'name':self.project.name}) @@ -80,6 +82,10 @@ def test_api_get_project_not_found(self): r_with_bad_key = self.client.get('/api/v1/gh-projects', {'giibbier':self.project.owner.login, 'name':self.project.name}) self.assertTrue(status.is_client_error(r_with_bad_key.status_code)) + def test_get_pr_stats(self): + r = self.client.get('/api/v1/gh-projects/%d/pull-requests'%self.django.id) + self.assertTrue(status.is_success(r.status_code), 'Status code was: %d' %r.status_code) + diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index a417025..e37a406 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -10,10 +10,15 @@ Business logic for api endpoints. """ -from rest_framework.mixins import ListModelMixin + +from datetime import timedelta +from django.utils import timezone +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.viewsets import GenericViewSet from rest_framework.exceptions import NotFound -from rest_framework.status import HTTP_404_NOT_FOUND +from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_200_OK +from rest_framework.response import Response +from rest_framework.decorators import detail_route from repo_health.gh_users.models import GhUser from .models import GhProject from .serializers import GhProjectSerializer @@ -31,3 +36,14 @@ def list(self, r, *args, **kwargs): else: response.data = response.data[0] return response + + @detail_route(url_path='pull-requests') + def pull_requests(self, *args, **kwargs): + repo = self.get_object() + now = timezone.now() + one_year_ago = now - timedelta(days=366) + print(repo.prs_to.distinct().count()) + print(repo.prs_to.filter(commits__created_at__lte=one_year_ago).distinct().count()) + return Response(HTTP_200_OK) + + diff --git a/repo_health/gh_pull_requests/models/GhPullRequest.py b/repo_health/gh_pull_requests/models/GhPullRequest.py index 5dc54f0..0a6e18e 100644 --- a/repo_health/gh_pull_requests/models/GhPullRequest.py +++ b/repo_health/gh_pull_requests/models/GhPullRequest.py @@ -18,21 +18,29 @@ class GhPullRequest(models.Model): head_repo = models.ForeignKey( 'gh_projects.GhProject', models.DO_NOTHING, blank=True, null=True, - related_name='head_repo' + related_name='prs_from' ) base_repo = models.ForeignKey( 'gh_projects.GhProject', models.DO_NOTHING, + related_name='prs_to', ) head_commit = models.ForeignKey( 'gh_commits.GhCommit', models.DO_NOTHING, blank=True, null=True, - related_name='head_commit' + related_name="commit_from" + ) + base_commit = models.ForeignKey('gh_commits.GhCommit', models.DO_NOTHING, + related_name="commit_to" ) - base_commit = models.ForeignKey('gh_commits.GhCommit', models.DO_NOTHING) user = models.ForeignKey('gh_users.GhUser', models.DO_NOTHING) pullreq_id = models.IntegerField() intra_branch = models.IntegerField() merged = models.IntegerField() + #Added M2M + commits = models.ManyToManyField('gh_commits.GhCommit', + through = 'gh_pull_requests.GhPullRequestCommit' + ) + def __str__(self): return "PR base project: %s" % self.base_repo.name From 665dcd5f50db74c1f70d981de9a823f13f7fe4c4 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Tue, 21 Feb 2017 22:47:59 -0600 Subject: [PATCH 32/99] Build array of pull request count per month. --- docs/rest_api/PullRequests.md | 3 ++- repo_health/gh_projects/views.py | 27 +++++++++++++++---- .../gh_pull_requests/models/GhPullRequest.py | 7 +++++ .../models/GhPullRequestHistory.py | 6 ++++- repo_health/settings.py | 2 +- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/docs/rest_api/PullRequests.md b/docs/rest_api/PullRequests.md index 0a298fd..3223b97 100644 --- a/docs/rest_api/PullRequests.md +++ b/docs/rest_api/PullRequests.md @@ -5,10 +5,11 @@ A GET request is made to: - `/api/v1/gh-projects//pull-requests` - Note the repo id embedded in the URL + ``` { "prs_count": int, - "prs_last_year: 12 element array, + "prs_last_year: [int] //12 element array, number of prs per month,oldest first, one year from latest_pr_created_at "latest_pr_created_at": datetime str, "contrib_most_prs": str - login, "prs_no_maintainer_comments": int, diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index e37a406..277ca02 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -11,7 +11,7 @@ """ -from datetime import timedelta +import datetime, calendar from django.utils import timezone from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.viewsets import GenericViewSet @@ -20,10 +20,12 @@ from rest_framework.response import Response from rest_framework.decorators import detail_route from repo_health.gh_users.models import GhUser +from repo_health.gh_pull_requests.models import GhPullRequestHistory from .models import GhProject from .serializers import GhProjectSerializer + class GhProjectViewSet(ListModelMixin, GenericViewSet): queryset = GhProject.objects.all() serializer_class = GhProjectSerializer @@ -40,10 +42,25 @@ def list(self, r, *args, **kwargs): @detail_route(url_path='pull-requests') def pull_requests(self, *args, **kwargs): repo = self.get_object() - now = timezone.now() - one_year_ago = now - timedelta(days=366) - print(repo.prs_to.distinct().count()) - print(repo.prs_to.filter(commits__created_at__lte=one_year_ago).distinct().count()) + one_year = datetime.timedelta(days=366) + + opened_histories = GhPullRequestHistory.objects.filter( + pull_request__base_repo = repo, + action = GhPullRequestHistory.OPENED_ACTION, + ).order_by('-created_at') + most_recent_history_created = opened_histories.first().created_at + + opened_prev_year = opened_histories.filter(created_at__gte=most_recent_history_created - one_year).distinct() + dt_to_filter = opened_prev_year.last().created_at + + opened_count_for_year = [] + for m in range(12): + days_in_mon = calendar.monthrange(dt_to_filter.year, dt_to_filter.month)[1] + opened_count_for_year.append(opened_prev_year.filter( + created_at__year=dt_to_filter.year, + created_at__month=dt_to_filter.month).count()) + dt_to_filter += datetime.timedelta(days = days_in_mon) + print (opened_count_for_year) return Response(HTTP_200_OK) diff --git a/repo_health/gh_pull_requests/models/GhPullRequest.py b/repo_health/gh_pull_requests/models/GhPullRequest.py index 0a6e18e..966fc27 100644 --- a/repo_health/gh_pull_requests/models/GhPullRequest.py +++ b/repo_health/gh_pull_requests/models/GhPullRequest.py @@ -44,6 +44,13 @@ class GhPullRequest(models.Model): def __str__(self): return "PR base project: %s" % self.base_repo.name + @property + def created_at(self): + """Convenience method to determine when pull request was created. + For now use the head commit's created_at field. + """ + return self.head_commit.created_at + class Meta: managed = False db_table = 'pull_requests' diff --git a/repo_health/gh_pull_requests/models/GhPullRequestHistory.py b/repo_health/gh_pull_requests/models/GhPullRequestHistory.py index 30ca0f2..53acf43 100644 --- a/repo_health/gh_pull_requests/models/GhPullRequestHistory.py +++ b/repo_health/gh_pull_requests/models/GhPullRequestHistory.py @@ -14,7 +14,11 @@ class GhPullRequestHistory(models.Model): - pull_request = models.ForeignKey('gh_pull_requests.GhPullRequest', models.DO_NOTHING) + OPENED_ACTION = 'opened' + CLOSED_ACTION = 'closed' + pull_request = models.ForeignKey('gh_pull_requests.GhPullRequest', models.DO_NOTHING, + related_name='history' + ) created_at = models.DateTimeField() ext_ref_id = models.CharField(max_length=24) action = models.CharField(max_length=255) diff --git a/repo_health/settings.py b/repo_health/settings.py index aedf512..98e85d5 100644 --- a/repo_health/settings.py +++ b/repo_health/settings.py @@ -118,7 +118,7 @@ USE_L10N = True -USE_TZ = True +USE_TZ = False # Static files (CSS, JavaScript, Images) From dc191d92acd5def90ac7bfeccb9d1800b93f037d Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 22 Feb 2017 21:46:59 -0600 Subject: [PATCH 33/99] PEP8 stuff PyCharm picked up. --- repo_health/gh_projects/views.py | 12 ++++-------- repo_health/index/views.py | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index 277ca02..08c6396 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -11,28 +11,26 @@ """ -import datetime, calendar -from django.utils import timezone -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin +import datetime +import calendar +from rest_framework.mixins import ListModelMixin from rest_framework.viewsets import GenericViewSet from rest_framework.exceptions import NotFound from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_200_OK from rest_framework.response import Response from rest_framework.decorators import detail_route -from repo_health.gh_users.models import GhUser from repo_health.gh_pull_requests.models import GhPullRequestHistory from .models import GhProject from .serializers import GhProjectSerializer - class GhProjectViewSet(ListModelMixin, GenericViewSet): queryset = GhProject.objects.all() serializer_class = GhProjectSerializer filter_fields = ('owner__login', 'name') def list(self, r, *args, **kwargs): - response = super().list(r, *args, **kwargs) + response = super().list(r, *args, **kwargs) if len(response.data) is not 1: raise NotFound('Repo not found', HTTP_404_NOT_FOUND) else: @@ -62,5 +60,3 @@ def pull_requests(self, *args, **kwargs): dt_to_filter += datetime.timedelta(days = days_in_mon) print (opened_count_for_year) return Response(HTTP_200_OK) - - diff --git a/repo_health/index/views.py b/repo_health/index/views.py index ef82638..b177991 100644 --- a/repo_health/index/views.py +++ b/repo_health/index/views.py @@ -4,7 +4,7 @@ from django.views.generic import TemplateView -# Create your views here. + class IndexView(TemplateView): template_name = 'index.html' From d460c2956e43bf032c25def2976aa6e2aecc5499 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 26 Feb 2017 01:50:03 -0600 Subject: [PATCH 34/99] Add some fields to the PR stats serializer. --- repo_health/gh_pull_requests/models/GhPullRequest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/repo_health/gh_pull_requests/models/GhPullRequest.py b/repo_health/gh_pull_requests/models/GhPullRequest.py index 966fc27..583e932 100644 --- a/repo_health/gh_pull_requests/models/GhPullRequest.py +++ b/repo_health/gh_pull_requests/models/GhPullRequest.py @@ -31,7 +31,9 @@ class GhPullRequest(models.Model): base_commit = models.ForeignKey('gh_commits.GhCommit', models.DO_NOTHING, related_name="commit_to" ) - user = models.ForeignKey('gh_users.GhUser', models.DO_NOTHING) + user = models.ForeignKey('gh_users.GhUser', models.DO_NOTHING, + related_name='pull_requests' + ) pullreq_id = models.IntegerField() intra_branch = models.IntegerField() merged = models.IntegerField() From ca09d148b26a8cb2a2c58d39810e073979c91d2c Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 26 Feb 2017 01:50:23 -0600 Subject: [PATCH 35/99] Add some fields to the PR stats serializer. Commit all files this time. --- repo_health/gh_commits/models/GhCommit.py | 6 +- repo_health/gh_projects/models/GhProject.py | 2 +- .../serializers/GhProjectSerializer.py | 4 +- repo_health/gh_projects/tests.py | 40 ++++++--- repo_health/gh_projects/views.py | 36 +++----- .../GhPullRequestStatsSerializer.py | 83 +++++++++++++++++++ .../gh_pull_requests/serializers/__init__.py | 13 +++ 7 files changed, 139 insertions(+), 45 deletions(-) create mode 100644 repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py create mode 100644 repo_health/gh_pull_requests/serializers/__init__.py diff --git a/repo_health/gh_commits/models/GhCommit.py b/repo_health/gh_commits/models/GhCommit.py index ca3771a..d5cdbb3 100644 --- a/repo_health/gh_commits/models/GhCommit.py +++ b/repo_health/gh_commits/models/GhCommit.py @@ -18,11 +18,11 @@ class GhCommit(models.Model): sha = models.CharField(unique=True, max_length=40, blank=True, null=True) author = models.ForeignKey( 'gh_users.GhUser', models.DO_NOTHING, - blank=True, null=True, related_name='author' + blank=True, null=True, related_name='authored_commits' ) committer = models.ForeignKey( 'gh_users.GhUser', models.DO_NOTHING, - blank=True, null=True, related_name="commits" + blank=True, null=True, related_name="committer_commits" ) project = models.ForeignKey( 'gh_projects.GhProject', models.DO_NOTHING, blank=True, null=True, @@ -31,7 +31,7 @@ class GhCommit(models.Model): created_at = models.DateTimeField() ext_ref_id = models.CharField(max_length=24) - #Added fields for many to many relationships + # Added fields for many to many relationships comment_users = models.ManyToManyField( "gh_users.GhUser", through="gh_commits.GhCommitComment" diff --git a/repo_health/gh_projects/models/GhProject.py b/repo_health/gh_projects/models/GhProject.py index 57031e8..7ba30b9 100644 --- a/repo_health/gh_projects/models/GhProject.py +++ b/repo_health/gh_projects/models/GhProject.py @@ -30,7 +30,7 @@ class GhProject(m.Model): ) deleted = m.IntegerField() - #M2M fields added + # M2M fields added commits_m2m = m.ManyToManyField( 'gh_commits.GhCommit', through='gh_projects.GhProjectCommit', diff --git a/repo_health/gh_projects/serializers/GhProjectSerializer.py b/repo_health/gh_projects/serializers/GhProjectSerializer.py index 5ef30d5..8cc30a6 100644 --- a/repo_health/gh_projects/serializers/GhProjectSerializer.py +++ b/repo_health/gh_projects/serializers/GhProjectSerializer.py @@ -14,6 +14,7 @@ from repo_health.gh_users.models import GhUser from ..models import GhProject + class GhProjectSerializer(ModelSerializer): _contribs_count = None _watch_not_contribs_count = None @@ -45,7 +46,6 @@ def __init__(self, *args, **kwargs): self._contribs_count = commit_users.count() self._latest_commit = commits.first().created_at self._orgs_of_contribs_count = GhUser.objects.filter(members__in=commit_users).exclude(id=repo.owner.id).count() - def get_orgs_of_contribs_count(self, repo): return self._orgs_of_contribs_count @@ -79,4 +79,4 @@ def get_forks_count(self, repo): class Meta: model = GhProject - exclude = ['commits_m2m', 'maintainers', 'watchers', 'url', 'forks',] \ No newline at end of file + exclude = ['commits_m2m', 'maintainers', 'watchers', 'url', 'forks', ] diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index b1c7ad3..9237fa5 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -11,8 +11,9 @@ """ -from django.urls import reverse +import datetime from django.test import TestCase, Client +from django.db import models as m from rest_framework import status from rest_framework.test import APITestCase from .models import GhProject, GhRepoLabel @@ -58,9 +59,11 @@ class GhProjectApiTest(APITestCase): """ project = None + def setUp(self): self.project = GhProject.objects.last() - #Django has a lot of pull requests + self.project_no_prs = GhProject.objects.annotate(prs_to_count=m.Count('prs_to')).order_by('prs_to_count').first() + # Django has a lot of pull requests self.django = GhProject.objects.get(name='django', owner__login='django') def test_api_get_project(self): @@ -70,23 +73,34 @@ def test_api_get_project(self): self.assertEqual(r.data['id'], self.project.id) def test_api_get_project_not_found(self): - #Test with a bad owner login + # Test with a bad owner login r_with_bad_owner = self.client.get('/api/v1/gh-projects', {'owner__login':'incoherehnet giibbuusrish', 'name':self.project.name}) self.assertTrue(status.is_client_error(r_with_bad_owner.status_code)) - #Test with a bad repo name - r_with_bad_repo = self.client.get('/api/v1/gh-projects', {'owner__login':self.project.owner.login, 'name':'gibiberishsh'}) + # Test with a bad repo name + r_with_bad_repo = self.client.get('/api/v1/gh-projects', { + 'owner__login': self.project.owner.login, 'name': 'gibiberishsh' + }) self.assertTrue(status.is_client_error(r_with_bad_repo.status_code)) - #Test with a bad param - r_with_bad_key = self.client.get('/api/v1/gh-projects', {'giibbier':self.project.owner.login, 'name':self.project.name}) + # Test with a bad param + r_with_bad_key = self.client.get('/api/v1/gh-projects', { + 'giibbier': self.project.owner.login, 'name': self.project.name + }) self.assertTrue(status.is_client_error(r_with_bad_key.status_code)) def test_get_pr_stats(self): - r = self.client.get('/api/v1/gh-projects/%d/pull-requests'%self.django.id) - self.assertTrue(status.is_success(r.status_code), 'Status code was: %d' %r.status_code) + r = self.client.get('/api/v1/gh-projects/%d/pull-requests' % self.django.id) + self.assertTrue(status.is_success(r.status_code), 'Status code was: %d' % r.status_code) + self.assertTrue(r.data['pr_count'] and isinstance(r.data['pr_count'], int)) + self.assertTrue(r.data['prs_last_year'] and isinstance(r.data['prs_last_year'], list)) + self.assertTrue(r.data['latest_or_created_at'] and isinstance(r.data['latest_or_created_at'], datetime.datetime)) + self.assertTrue(r.data['contrib_most_prs'] and isinstance(r.data['contrib_most_prs'], str)) + import pprint as pp + pp.pprint(r.data) + + # Test a repo with no prs to be sure no errors are thrown + self.client.get('/api/v1/gh-projects/%d/pull-requests' % self.project_no_prs.id) + + - - - - \ No newline at end of file diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index 08c6396..fb618ab 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -11,15 +11,14 @@ """ -import datetime -import calendar +from django.db import models from rest_framework.mixins import ListModelMixin from rest_framework.viewsets import GenericViewSet from rest_framework.exceptions import NotFound -from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_200_OK +from rest_framework.status import HTTP_404_NOT_FOUND from rest_framework.response import Response from rest_framework.decorators import detail_route -from repo_health.gh_pull_requests.models import GhPullRequestHistory +from repo_health.gh_pull_requests.serializers import GhPullRequestStatsSerializer from .models import GhProject from .serializers import GhProjectSerializer @@ -36,27 +35,12 @@ def list(self, r, *args, **kwargs): else: response.data = response.data[0] return response - + @detail_route(url_path='pull-requests') def pull_requests(self, *args, **kwargs): - repo = self.get_object() - one_year = datetime.timedelta(days=366) - - opened_histories = GhPullRequestHistory.objects.filter( - pull_request__base_repo = repo, - action = GhPullRequestHistory.OPENED_ACTION, - ).order_by('-created_at') - most_recent_history_created = opened_histories.first().created_at - - opened_prev_year = opened_histories.filter(created_at__gte=most_recent_history_created - one_year).distinct() - dt_to_filter = opened_prev_year.last().created_at - - opened_count_for_year = [] - for m in range(12): - days_in_mon = calendar.monthrange(dt_to_filter.year, dt_to_filter.month)[1] - opened_count_for_year.append(opened_prev_year.filter( - created_at__year=dt_to_filter.year, - created_at__month=dt_to_filter.month).count()) - dt_to_filter += datetime.timedelta(days = days_in_mon) - print (opened_count_for_year) - return Response(HTTP_200_OK) + repo = GhProject.objects\ + .annotate(pr_count=models.Count('prs_to'))\ + .get(pk=kwargs['pk']) + + pr_stats = GhPullRequestStatsSerializer(repo) + return Response(pr_stats.data) diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py new file mode 100644 index 0000000..8e9dd6e --- /dev/null +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -0,0 +1,83 @@ +""" +serializers.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Serializers for pull requests. +""" + +import datetime +import calendar +from django.db import models +from rest_framework import serializers as s +from repo_health.gh_users.models import GhUser +from ..models import GhPullRequestHistory, GhPullRequest + + +class GhPullRequestStatsSerializer(s.Serializer): + _most_recent_history = None + _opened_histories = None + _contrib_most_prs = None + + pr_count = s.SerializerMethodField() + prs_last_year = s.SerializerMethodField() + latest_or_created_at = s.SerializerMethodField() + contrib_most_prs = s.SerializerMethodField() + # prs_no_maintainer_comments = s.SerializerMethodField() + # prs_no_comments = s.SerializerMethodField() + # avg_lifetime = s.SerializerMethodField() + # not_maintainer_prs = s.SerializerMethodField() + # avg_comment_per_pr = s.SerializerMethodField() + # prs_from_outside_org = s.SerializerMethodField() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + repo = args[0] + self._opened_histories = GhPullRequestHistory.objects.filter( + pull_request__base_repo=repo, + action=GhPullRequestHistory.OPENED_ACTION, + ).order_by('-created_at') + + self._most_recent_history = self._opened_histories.first() + # self._most_recent_history_created = self._opened_histories.first().created_at if + + # Get user with the most pulll requests for this repo + self._contrib_most_prs = GhUser.objects.filter( + pull_requests__base_repo=repo, + ).annotate( + contrib_prs=models.Count('pull_requests') + ).order_by('-contrib_prs').first() + + def get_pr_count(self, repo): + return repo.pr_count + + def get_prs_last_year(self, repo): + one_year = datetime.timedelta(days=366) + opened_count_for_year = [] + + if self._most_recent_history: + opened_prev_year = self._opened_histories.filter(created_at__gte=self._most_recent_history.created_at - one_year) + dt_to_filter = opened_prev_year.last().created_at + + for m in range(12): + days_in_mon = calendar.monthrange(dt_to_filter.year, dt_to_filter.month)[1] + opened_count_for_year.append(opened_prev_year.filter( + created_at__year=dt_to_filter.year, + created_at__month=dt_to_filter.month).count()) + dt_to_filter += datetime.timedelta(days=days_in_mon) + return opened_count_for_year + + def get_latest_or_created_at(self, repo): + return self._most_recent_history.created_at if self._most_recent_history else None + + def get_contrib_most_prs(self, repo): + return self._contrib_most_prs.login if self._contrib_most_prs else None + + class Meta: + model = 'gh_projects.GhProject' + fields = ('pr_count', ) + diff --git a/repo_health/gh_pull_requests/serializers/__init__.py b/repo_health/gh_pull_requests/serializers/__init__.py new file mode 100644 index 0000000..05e44e3 --- /dev/null +++ b/repo_health/gh_pull_requests/serializers/__init__.py @@ -0,0 +1,13 @@ +""" +__init__.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Import all serializers in the gh_pull_requests package here. +""" + +from .GhPullRequestStatsSerializer import GhPullRequestStatsSerializer \ No newline at end of file From 34a6484cb8001fb37f37de00b979e974e2982807 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 26 Feb 2017 18:46:45 -0600 Subject: [PATCH 36/99] Trying to develop aggragation for average pr lifetime instead of iterating large querysets. --- docs/rest_api/PullRequests.md | 10 +++- docs/rest_api/Repos.md | 7 ++- repo_health/gh_projects/tests.py | 4 +- .../gh_pull_requests/models/GhPullRequest.py | 21 +++++++-- .../models/GhPullRequestComment.py | 5 +- .../models/GhPullRequestHistory.py | 2 + .../GhPullRequestStatsSerializer.py | 47 ++++++++++++++++--- repo_health/gh_users/models/GhUser.py | 13 +++++ 8 files changed, 94 insertions(+), 15 deletions(-) diff --git a/docs/rest_api/PullRequests.md b/docs/rest_api/PullRequests.md index 3223b97..0f2aa88 100644 --- a/docs/rest_api/PullRequests.md +++ b/docs/rest_api/PullRequests.md @@ -17,6 +17,12 @@ A GET request is made to: "avg_lifetime": str, "not_maintainer_prs": int, "avg_comment_per_pr": float, - "prs_from_outside_org": int + "prs_from_outside_org": int, + "maintainers_count: int, + "is_org": bool } -``` \ No newline at end of file +``` + +## Possilble future metrics + +- upstream/downstream pr count and count of merged diff --git a/docs/rest_api/Repos.md b/docs/rest_api/Repos.md index e780b7a..f0a5781 100644 --- a/docs/rest_api/Repos.md +++ b/docs/rest_api/Repos.md @@ -30,4 +30,9 @@ URL: "owned_by_org": bool, "forks_count": int } - ``` \ No newline at end of file + ``` + + ## Future Metric possibilities + +- maintainers count per month for past year to track project growth +- org members per month over past year to track org growth diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 9237fa5..58a39e5 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -94,8 +94,10 @@ def test_get_pr_stats(self): self.assertTrue(status.is_success(r.status_code), 'Status code was: %d' % r.status_code) self.assertTrue(r.data['pr_count'] and isinstance(r.data['pr_count'], int)) self.assertTrue(r.data['prs_last_year'] and isinstance(r.data['prs_last_year'], list)) - self.assertTrue(r.data['latest_or_created_at'] and isinstance(r.data['latest_or_created_at'], datetime.datetime)) + self.assertTrue(r.data.get('latest_pr_created_at') and isinstance(r.data['latest_pr_created_at'], datetime.datetime)) self.assertTrue(r.data['contrib_most_prs'] and isinstance(r.data['contrib_most_prs'], str)) + self.assertTrue(r.data.get('prs_no_maintainer_comments') and isinstance(r.data['prs_no_maintainer_comments'], int)) + import pprint as pp pp.pprint(r.data) diff --git a/repo_health/gh_pull_requests/models/GhPullRequest.py b/repo_health/gh_pull_requests/models/GhPullRequest.py index 583e932..b069c69 100644 --- a/repo_health/gh_pull_requests/models/GhPullRequest.py +++ b/repo_health/gh_pull_requests/models/GhPullRequest.py @@ -13,6 +13,7 @@ from django.db import models +from .GhPullRequestHistory import GhPullRequestHistory class GhPullRequest(models.Model): @@ -40,7 +41,11 @@ class GhPullRequest(models.Model): #Added M2M commits = models.ManyToManyField('gh_commits.GhCommit', - through = 'gh_pull_requests.GhPullRequestCommit' + through ='gh_pull_requests.GhPullRequestCommit' + ) + + comment_users = models.ManyToManyField('gh_users.GhUser', + through='gh_pull_requests.GhPullRequestComment' ) def __str__(self): @@ -49,9 +54,19 @@ def __str__(self): @property def created_at(self): """Convenience method to determine when pull request was created. - For now use the head commit's created_at field. """ - return self.head_commit.created_at + return self.history.filter( + action=GhPullRequestHistory.OPENED_ACTION, + ).order_by('created_at').first().created_at + + @property + def closed_at(self): + hs = self.history.filter( + models.Q(action=GhPullRequestHistory.CLOSED_ACTION) | models.Q( + action=GhPullRequestHistory.MERGED_ACTION), + ).order_by('created_at').first() + if hs: + return hs.created_at class Meta: managed = False diff --git a/repo_health/gh_pull_requests/models/GhPullRequestComment.py b/repo_health/gh_pull_requests/models/GhPullRequestComment.py index 08f7742..8a7e79a 100644 --- a/repo_health/gh_pull_requests/models/GhPullRequestComment.py +++ b/repo_health/gh_pull_requests/models/GhPullRequestComment.py @@ -14,7 +14,10 @@ class GhPullRequestComment(models.Model): - pull_request = models.ForeignKey('gh_pull_requests.GhPullRequest', models.DO_NOTHING) + pull_request = models.ForeignKey( + 'gh_pull_requests.GhPullRequest', models.DO_NOTHING, + related_name='comments' + ) user = models.ForeignKey('gh_users.GhUser', models.DO_NOTHING) comment_id = models.TextField() position = models.IntegerField(blank=True, null=True) diff --git a/repo_health/gh_pull_requests/models/GhPullRequestHistory.py b/repo_health/gh_pull_requests/models/GhPullRequestHistory.py index 53acf43..790ba27 100644 --- a/repo_health/gh_pull_requests/models/GhPullRequestHistory.py +++ b/repo_health/gh_pull_requests/models/GhPullRequestHistory.py @@ -16,6 +16,8 @@ class GhPullRequestHistory(models.Model): OPENED_ACTION = 'opened' CLOSED_ACTION = 'closed' + MERGED_ACTION = 'merged' + pull_request = models.ForeignKey('gh_pull_requests.GhPullRequest', models.DO_NOTHING, related_name='history' ) diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 8e9dd6e..a220c3e 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -22,14 +22,17 @@ class GhPullRequestStatsSerializer(s.Serializer): _most_recent_history = None _opened_histories = None _contrib_most_prs = None + _maintainers = None + _maintainers_count = None pr_count = s.SerializerMethodField() prs_last_year = s.SerializerMethodField() - latest_or_created_at = s.SerializerMethodField() + latest_pr_created_at = s.SerializerMethodField() contrib_most_prs = s.SerializerMethodField() - # prs_no_maintainer_comments = s.SerializerMethodField() - # prs_no_comments = s.SerializerMethodField() - # avg_lifetime = s.SerializerMethodField() + prs_no_maintainer_comments = s.SerializerMethodField() + maintainers_count = s.SerializerMethodField() + prs_no_comments = s.SerializerMethodField() + avg_lifetime = s.SerializerMethodField() # not_maintainer_prs = s.SerializerMethodField() # avg_comment_per_pr = s.SerializerMethodField() # prs_from_outside_org = s.SerializerMethodField() @@ -43,15 +46,16 @@ def __init__(self, *args, **kwargs): ).order_by('-created_at') self._most_recent_history = self._opened_histories.first() - # self._most_recent_history_created = self._opened_histories.first().created_at if - # Get user with the most pulll requests for this repo + # Get user with the most pull requests for this repo self._contrib_most_prs = GhUser.objects.filter( pull_requests__base_repo=repo, ).annotate( contrib_prs=models.Count('pull_requests') ).order_by('-contrib_prs').first() + self._maintainers = repo.maintainers.all() + def get_pr_count(self, repo): return repo.pr_count @@ -71,12 +75,41 @@ def get_prs_last_year(self, repo): dt_to_filter += datetime.timedelta(days=days_in_mon) return opened_count_for_year - def get_latest_or_created_at(self, repo): + def get_latest_pr_created_at(self, repo): return self._most_recent_history.created_at if self._most_recent_history else None def get_contrib_most_prs(self, repo): return self._contrib_most_prs.login if self._contrib_most_prs else None + def get_prs_no_maintainer_comments(self, repo): + return repo.prs_to.exclude(comment_users__in=self._maintainers).count() + + def get_maintainers_count(self, repo): + return self._maintainers.count() + + def get_prs_no_comments(self, repo): + return repo.prs_to.annotate(comments_count=models.Count('comments')).filter(comments_count=0).count() + + def get_avg_lifetime(self, repo): + avg = 0 + if repo.pr_count > 0: + td = datetime.timedelta() + for p in repo.prs_to.all(): + if p.closed_at: + td += p.closed_at - p.created_at + avg = (td / repo.pr_count).days + + # agg = repo.prs_to \ + # .annotate(closed_at=models.When(history__action=GhPullRequestHistory.CLOSED_ACTION, then=models.F('history__created_at'))) \ + # .annotate(created_at=models.When(history__action=GhPullRequestHistory.OPENED_ACTION, then=models.F('history__created_at')))\ + # .annotate(elapsed=models.F('closed_at') - models.F('created_at'))\ + # .values('created_at', 'closed_at', 'id', 'elapsed') + # print(agg) + # for a in agg: + # if a.get('elapsed'): + # print("Has elapsed:" + a) + return avg + class Meta: model = 'gh_projects.GhProject' fields = ('pr_count', ) diff --git a/repo_health/gh_users/models/GhUser.py b/repo_health/gh_users/models/GhUser.py index 024ebdd..3bd911e 100644 --- a/repo_health/gh_users/models/GhUser.py +++ b/repo_health/gh_users/models/GhUser.py @@ -1,3 +1,16 @@ +""" +GhUser.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +GitHub User model. +""" + + from django.db import models as m From c4199661def2443e69d601c407c77573f191da99 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Tue, 28 Feb 2017 12:42:06 -0600 Subject: [PATCH 37/99] Initial addition of angular-material --- .../index/static/client/assets/global.css | 2 +- .../static/client/assets/styles/styles.css | 10 +++---- .../assets/vendor/angular-material.min.css | 6 ++++ .../client/src/components/search/search.html | 18 +++++------ .../index/static/client/src/main.module.js | 2 ++ repo_health/index/static/package.json | 3 ++ repo_health/index/templates/index.html | 30 +++++++++---------- 7 files changed, 40 insertions(+), 31 deletions(-) create mode 100644 repo_health/index/static/client/assets/vendor/angular-material.min.css diff --git a/repo_health/index/static/client/assets/global.css b/repo_health/index/static/client/assets/global.css index 1669ae1..6174089 100644 --- a/repo_health/index/static/client/assets/global.css +++ b/repo_health/index/static/client/assets/global.css @@ -10,5 +10,5 @@ * This file will contain all of the styles imported in the order they need to be */ -@import 'vendor/bootstrap.min.css'; +@import 'vendor/angular-material.min.css'; @import 'styles/styles.css'; \ No newline at end of file diff --git a/repo_health/index/static/client/assets/styles/styles.css b/repo_health/index/static/client/assets/styles/styles.css index 38d967e..9edc719 100644 --- a/repo_health/index/static/client/assets/styles/styles.css +++ b/repo_health/index/static/client/assets/styles/styles.css @@ -10,17 +10,17 @@ * This file holds the general css for the application */ +.text-center { + text-align: center; +} + .search-repo { width: 75%; - height: 200px; + height: 300px; position: absolute; top: 0; bottom: 15%; left: 0; right: 0; margin: auto; -} - -.search-button { - margin-top: 15px; } \ No newline at end of file diff --git a/repo_health/index/static/client/assets/vendor/angular-material.min.css b/repo_health/index/static/client/assets/vendor/angular-material.min.css new file mode 100644 index 0000000..1a10d13 --- /dev/null +++ b/repo_health/index/static/client/assets/vendor/angular-material.min.css @@ -0,0 +1,6 @@ +/*! + * Angular Material Design + * https://github.com/angular/material + * @license MIT + * v1.1.3 + */body,html{height:100%;position:relative}body{margin:0;padding:0}[tabindex="-1"]:focus{outline:none}.inset{padding:10px}a.md-no-style,button.md-no-style{font-weight:400;background-color:inherit;text-align:left;border:none;padding:0;margin:0}button,input,select,textarea{vertical-align:baseline}button,html input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled]{cursor:default}textarea{vertical-align:top;overflow:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box;-webkit-box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input:-webkit-autofill{text-shadow:none}.md-visually-hidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;text-transform:none;width:1px}.md-shadow{position:absolute;top:0;left:0;bottom:0;right:0;border-radius:inherit;pointer-events:none}.md-shadow-bottom-z-1{box-shadow:0 2px 5px 0 rgba(0,0,0,.26)}.md-shadow-bottom-z-2{box-shadow:0 4px 8px 0 rgba(0,0,0,.4)}.md-shadow-animated.md-shadow{-webkit-transition:box-shadow .28s cubic-bezier(.4,0,.2,1);transition:box-shadow .28s cubic-bezier(.4,0,.2,1)}.md-ripple-container{pointer-events:none;position:absolute;overflow:hidden;left:0;top:0;width:100%;height:100%;-webkit-transition:all .55s cubic-bezier(.25,.8,.25,1);transition:all .55s cubic-bezier(.25,.8,.25,1)}.md-ripple{position:absolute;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transform-origin:50% 50%;transform-origin:50% 50%;opacity:0;border-radius:50%}.md-ripple.md-ripple-placed{-webkit-transition:margin .9s cubic-bezier(.25,.8,.25,1),border .9s cubic-bezier(.25,.8,.25,1),width .9s cubic-bezier(.25,.8,.25,1),height .9s cubic-bezier(.25,.8,.25,1),opacity .9s cubic-bezier(.25,.8,.25,1),-webkit-transform .9s cubic-bezier(.25,.8,.25,1);transition:margin .9s cubic-bezier(.25,.8,.25,1),border .9s cubic-bezier(.25,.8,.25,1),width .9s cubic-bezier(.25,.8,.25,1),height .9s cubic-bezier(.25,.8,.25,1),opacity .9s cubic-bezier(.25,.8,.25,1),-webkit-transform .9s cubic-bezier(.25,.8,.25,1);transition:margin .9s cubic-bezier(.25,.8,.25,1),border .9s cubic-bezier(.25,.8,.25,1),width .9s cubic-bezier(.25,.8,.25,1),height .9s cubic-bezier(.25,.8,.25,1),opacity .9s cubic-bezier(.25,.8,.25,1),transform .9s cubic-bezier(.25,.8,.25,1);transition:margin .9s cubic-bezier(.25,.8,.25,1),border .9s cubic-bezier(.25,.8,.25,1),width .9s cubic-bezier(.25,.8,.25,1),height .9s cubic-bezier(.25,.8,.25,1),opacity .9s cubic-bezier(.25,.8,.25,1),transform .9s cubic-bezier(.25,.8,.25,1),-webkit-transform .9s cubic-bezier(.25,.8,.25,1)}.md-ripple.md-ripple-scaled{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.md-ripple.md-ripple-active,.md-ripple.md-ripple-full,.md-ripple.md-ripple-visible{opacity:.2}.md-ripple.md-ripple-remove{-webkit-animation:md-remove-ripple .9s cubic-bezier(.25,.8,.25,1);animation:md-remove-ripple .9s cubic-bezier(.25,.8,.25,1)}@-webkit-keyframes md-remove-ripple{0%{opacity:.15}to{opacity:0}}@keyframes md-remove-ripple{0%{opacity:.15}to{opacity:0}}.md-padding{padding:8px}.md-margin{margin:8px}.md-scroll-mask{position:absolute;background-color:transparent;top:0;right:0;bottom:0;left:0;z-index:50}.md-scroll-mask>.md-scroll-mask-bar{display:block;position:absolute;background-color:#fafafa;right:0;top:0;bottom:0;z-index:65;box-shadow:inset 0 0 1px rgba(0,0,0,.3)}.md-no-momentum{-webkit-overflow-scrolling:auto}.md-no-flicker{-webkit-filter:blur(0)}@media (min-width:960px){.md-padding{padding:16px}}body[dir=ltr],body[dir=rtl],html[dir=ltr],html[dir=rtl]{unicode-bidi:embed}bdo[dir=rtl]{direction:rtl}bdo[dir=ltr],bdo[dir=rtl]{unicode-bidi:bidi-override}bdo[dir=ltr]{direction:ltr}body,html{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;min-height:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.md-display-4{font-size:112px;font-weight:300;letter-spacing:-.01em;line-height:112px}.md-display-3{font-size:56px;font-weight:400;letter-spacing:-.005em;line-height:56px}.md-display-2{font-size:45px;font-weight:400;line-height:64px}.md-display-1{font-size:34px;font-weight:400;line-height:40px}.md-headline{font-size:24px;font-weight:400;line-height:32px}.md-title{font-size:20px;font-weight:500;letter-spacing:.005em}.md-subhead{font-size:16px;line-height:24px}.md-body-1,.md-subhead{font-weight:400;letter-spacing:.01em}.md-body-1{font-size:14px;line-height:20px}.md-body-2{font-size:14px;font-weight:500;letter-spacing:.01em;line-height:24px}.md-caption{font-size:12px;letter-spacing:.02em}.md-button{letter-spacing:.01em}button,html,input,select,textarea{font-family:Roboto,Helvetica Neue,sans-serif}button,input,select,textarea{font-size:100%}.md-panel-outer-wrapper{height:100%;left:0;position:absolute;top:0;width:100%}._md-panel-hidden{display:none}._md-panel-fullscreen{border-radius:0;left:0;min-height:100%;min-width:100%;position:fixed;top:0}._md-panel-shown .md-panel{opacity:1;-webkit-transition:none;transition:none}.md-panel{opacity:0;position:fixed}.md-panel._md-panel-shown{opacity:1;-webkit-transition:none;transition:none}.md-panel._md-panel-animate-enter{opacity:1;-webkit-transition:all .3s cubic-bezier(0,0,.2,1);transition:all .3s cubic-bezier(0,0,.2,1)}.md-panel._md-panel-animate-leave{opacity:1;-webkit-transition:all .3s cubic-bezier(.4,0,1,1);transition:all .3s cubic-bezier(.4,0,1,1)}.md-panel._md-panel-animate-fade-out,.md-panel._md-panel-animate-scale-out{opacity:0}.md-panel._md-panel-backdrop{height:100%;position:absolute;width:100%}.md-panel._md-opaque-enter{opacity:.48;-webkit-transition:opacity .3s cubic-bezier(0,0,.2,1);transition:opacity .3s cubic-bezier(0,0,.2,1)}.md-panel._md-opaque-leave{-webkit-transition:opacity .3s cubic-bezier(.4,0,1,1);transition:opacity .3s cubic-bezier(.4,0,1,1)}md-autocomplete{border-radius:2px;display:block;height:40px;position:relative;overflow:visible;min-width:190px}md-autocomplete[disabled] input{cursor:default}md-autocomplete[md-floating-label]{border-radius:0;background:transparent;height:auto}md-autocomplete[md-floating-label] md-input-container{padding-bottom:0}md-autocomplete[md-floating-label] md-autocomplete-wrap{height:auto}md-autocomplete[md-floating-label] .md-show-clear-button button{display:block;position:absolute;right:0;top:20px;width:30px;height:30px}md-autocomplete[md-floating-label] .md-show-clear-button input{padding-right:30px}[dir=rtl] md-autocomplete[md-floating-label] .md-show-clear-button input{padding-right:0;padding-left:30px}md-autocomplete md-autocomplete-wrap{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row;box-sizing:border-box;position:relative;overflow:visible;height:40px}md-autocomplete md-autocomplete-wrap.md-menu-showing{z-index:51}md-autocomplete md-autocomplete-wrap input,md-autocomplete md-autocomplete-wrap md-input-container{-webkit-box-flex:1;-webkit-flex:1 1 0%;flex:1 1 0%;box-sizing:border-box;min-width:0}md-autocomplete md-autocomplete-wrap md-progress-linear{position:absolute;bottom:-2px;left:0}md-autocomplete md-autocomplete-wrap md-progress-linear.md-inline{bottom:40px;right:2px;left:2px;width:auto}md-autocomplete md-autocomplete-wrap md-progress-linear .md-mode-indeterminate{position:absolute;top:0;left:0;width:100%;height:3px;-webkit-transition:none;transition:none}md-autocomplete md-autocomplete-wrap md-progress-linear .md-mode-indeterminate .md-container{-webkit-transition:none;transition:none;height:3px}md-autocomplete md-autocomplete-wrap md-progress-linear .md-mode-indeterminate.ng-enter{-webkit-transition:opacity .15s linear;transition:opacity .15s linear}md-autocomplete md-autocomplete-wrap md-progress-linear .md-mode-indeterminate.ng-enter.ng-enter-active{opacity:1}md-autocomplete md-autocomplete-wrap md-progress-linear .md-mode-indeterminate.ng-leave{-webkit-transition:opacity .15s linear;transition:opacity .15s linear}md-autocomplete md-autocomplete-wrap md-progress-linear .md-mode-indeterminate.ng-leave.ng-leave-active{opacity:0}md-autocomplete input:not(.md-input){font-size:14px;box-sizing:border-box;border:none;box-shadow:none;outline:none;background:transparent;width:100%;padding:0 15px;line-height:40px;height:40px}md-autocomplete input:not(.md-input)::-ms-clear{display:none}md-autocomplete .md-show-clear-button button{position:relative;line-height:20px;text-align:center;width:30px;height:30px;cursor:pointer;border:none;border-radius:50%;padding:0;font-size:12px;background:transparent;margin:auto 5px}md-autocomplete .md-show-clear-button button:after{content:"";position:absolute;top:-6px;right:-6px;bottom:-6px;left:-6px;border-radius:50%;-webkit-transform:scale(0);transform:scale(0);opacity:0;-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1)}md-autocomplete .md-show-clear-button button:focus{outline:none}md-autocomplete .md-show-clear-button button:focus:after{-webkit-transform:scale(1);transform:scale(1);opacity:1}md-autocomplete .md-show-clear-button button md-icon{position:absolute;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0) scale(.9);transform:translate3d(-50%,-50%,0) scale(.9)}md-autocomplete .md-show-clear-button button md-icon path{stroke-width:0}md-autocomplete .md-show-clear-button button.ng-enter{-webkit-transform:scale(0);transform:scale(0);-webkit-transition:-webkit-transform .15s ease-out;transition:-webkit-transform .15s ease-out;transition:transform .15s ease-out;transition:transform .15s ease-out,-webkit-transform .15s ease-out}md-autocomplete .md-show-clear-button button.ng-enter.ng-enter-active{-webkit-transform:scale(1);transform:scale(1)}md-autocomplete .md-show-clear-button button.ng-leave{-webkit-transition:-webkit-transform .15s ease-out;transition:-webkit-transform .15s ease-out;transition:transform .15s ease-out;transition:transform .15s ease-out,-webkit-transform .15s ease-out}md-autocomplete .md-show-clear-button button.ng-leave.ng-leave-active{-webkit-transform:scale(0);transform:scale(0)}@media screen and (-ms-high-contrast:active){md-autocomplete input{border:1px solid #fff}md-autocomplete li:focus{color:#fff}}.md-virtual-repeat-container.md-autocomplete-suggestions-container{position:absolute;box-shadow:0 2px 5px rgba(0,0,0,.25);z-index:100;height:100%}.md-virtual-repeat-container.md-not-found{height:48px}.md-autocomplete-suggestions{margin:0;list-style:none;padding:0}.md-autocomplete-suggestions li{font-size:14px;overflow:hidden;padding:0 15px;line-height:48px;height:48px;-webkit-transition:background .15s linear;transition:background .15s linear;margin:0;white-space:nowrap;text-overflow:ellipsis}.md-autocomplete-suggestions li:focus{outline:none}.md-autocomplete-suggestions li:not(.md-not-found-wrapper){cursor:pointer}@media screen and (-ms-high-contrast:active){.md-autocomplete-suggestions,md-autocomplete{border:1px solid #fff}}button.md-button::-moz-focus-inner{border:0}.md-button{display:inline-block;position:relative;cursor:pointer;min-height:36px;min-width:88px;line-height:36px;vertical-align:middle;-webkit-box-align:center;-webkit-align-items:center;align-items:center;text-align:center;border-radius:2px;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:none;border:0;padding:0 6px;margin:6px 8px;background:transparent;color:currentColor;white-space:nowrap;text-transform:uppercase;font-weight:500;font-size:14px;font-style:inherit;font-variant:inherit;font-family:inherit;text-decoration:none;overflow:hidden;-webkit-transition:box-shadow .4s cubic-bezier(.25,.8,.25,1),background-color .4s cubic-bezier(.25,.8,.25,1);transition:box-shadow .4s cubic-bezier(.25,.8,.25,1),background-color .4s cubic-bezier(.25,.8,.25,1)}.md-dense :not(.md-dense-disabled) .md-button:not(.md-dense-disabled),.md-dense>.md-button:not(.md-dense-disabled){min-height:32px;line-height:32px;font-size:13px}.md-button:focus{outline:none}.md-button:focus,.md-button:hover{text-decoration:none}.md-button.ng-hide,.md-button.ng-leave{-webkit-transition:none;transition:none}.md-button.md-cornered{border-radius:0}.md-button.md-icon{padding:0;background:none}.md-button.md-raised:not([disabled]){box-shadow:0 2px 5px 0 rgba(0,0,0,.26)}.md-button.md-icon-button{margin:0 6px;height:40px;min-width:0;line-height:24px;padding:8px;width:40px;border-radius:50%}.md-button.md-icon-button .md-ripple-container{border-radius:50%;background-clip:padding-box;overflow:hidden;-webkit-mask-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC")}.md-button.md-fab{z-index:20;line-height:56px;min-width:0;width:56px;height:56px;vertical-align:middle;box-shadow:0 2px 5px 0 rgba(0,0,0,.26);border-radius:50%;background-clip:padding-box;overflow:hidden;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-property:background-color,box-shadow,-webkit-transform;transition-property:background-color,box-shadow,-webkit-transform;transition-property:background-color,box-shadow,transform;transition-property:background-color,box-shadow,transform,-webkit-transform}.md-button.md-fab.md-fab-bottom-right{top:auto;right:20px;bottom:20px;left:auto;position:absolute}.md-button.md-fab.md-fab-bottom-left{top:auto;right:auto;bottom:20px;left:20px;position:absolute}.md-button.md-fab.md-fab-top-right{top:20px;right:20px;bottom:auto;left:auto;position:absolute}.md-button.md-fab.md-fab-top-left{top:20px;right:auto;bottom:auto;left:20px;position:absolute}.md-button.md-fab .md-ripple-container{border-radius:50%;background-clip:padding-box;overflow:hidden;-webkit-mask-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC")}.md-button.md-fab.md-mini{line-height:40px;width:40px;height:40px}.md-button.md-fab.ng-hide,.md-button.md-fab.ng-leave{-webkit-transition:none;transition:none}.md-button:not([disabled]).md-fab.md-focused,.md-button:not([disabled]).md-raised.md-focused{box-shadow:0 2px 5px 0 rgba(0,0,0,.26)}.md-button:not([disabled]).md-fab:active,.md-button:not([disabled]).md-raised:active{box-shadow:0 4px 8px 0 rgba(0,0,0,.4)}.md-button .md-ripple-container{border-radius:2px;background-clip:padding-box;overflow:hidden;-webkit-mask-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC")}.md-button.md-icon-button md-icon,button.md-button.md-fab md-icon{display:block}.md-toast-open-top .md-button.md-fab-top-left,.md-toast-open-top .md-button.md-fab-top-right{-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transform:translate3d(0,42px,0);transform:translate3d(0,42px,0)}.md-toast-open-top .md-button.md-fab-top-left:not([disabled]).md-focused,.md-toast-open-top .md-button.md-fab-top-left:not([disabled]):hover,.md-toast-open-top .md-button.md-fab-top-right:not([disabled]).md-focused,.md-toast-open-top .md-button.md-fab-top-right:not([disabled]):hover{-webkit-transform:translate3d(0,41px,0);transform:translate3d(0,41px,0)}.md-toast-open-bottom .md-button.md-fab-bottom-left,.md-toast-open-bottom .md-button.md-fab-bottom-right{-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transform:translate3d(0,-42px,0);transform:translate3d(0,-42px,0)}.md-toast-open-bottom .md-button.md-fab-bottom-left:not([disabled]).md-focused,.md-toast-open-bottom .md-button.md-fab-bottom-left:not([disabled]):hover,.md-toast-open-bottom .md-button.md-fab-bottom-right:not([disabled]).md-focused,.md-toast-open-bottom .md-button.md-fab-bottom-right:not([disabled]):hover{-webkit-transform:translate3d(0,-43px,0);transform:translate3d(0,-43px,0)}.md-button-group{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-flex:1;-webkit-flex:1;flex:1;width:100%}.md-button-group>.md-button{-webkit-box-flex:1;-webkit-flex:1;flex:1;display:block;overflow:hidden;width:0;border-width:1px 0 1px 1px;border-radius:0;text-align:center;text-overflow:ellipsis;white-space:nowrap}.md-button-group>.md-button:first-child{border-radius:2px 0 0 2px}.md-button-group>.md-button:last-child{border-right-width:1px;border-radius:0 2px 2px 0}@media screen and (-ms-high-contrast:active){.md-button.md-fab,.md-button.md-raised{border:1px solid #fff}}md-bottom-sheet{position:absolute;left:0;right:0;bottom:0;padding:8px 16px 88px;z-index:70;border-top-width:1px;border-top-style:solid;-webkit-transform:translate3d(0,80px,0);transform:translate3d(0,80px,0);-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform}md-bottom-sheet.md-has-header{padding-top:0}md-bottom-sheet.ng-enter{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}md-bottom-sheet.ng-enter-active{opacity:1;display:block;-webkit-transform:translate3d(0,80px,0)!important;transform:translate3d(0,80px,0)!important}md-bottom-sheet.ng-leave-active{-webkit-transform:translate3d(0,100%,0)!important;transform:translate3d(0,100%,0)!important;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2)}md-bottom-sheet .md-subheader{background-color:transparent;font-family:Roboto,Helvetica Neue,sans-serif;line-height:56px;padding:0;white-space:nowrap}md-bottom-sheet md-inline-icon{display:inline-block;height:24px;width:24px;fill:#444}md-bottom-sheet md-list-item{display:-webkit-box;display:-webkit-flex;display:flex;outline:none}md-bottom-sheet md-list-item:hover{cursor:pointer}md-bottom-sheet.md-list md-list-item{padding:0;-webkit-box-align:center;-webkit-align-items:center;align-items:center;height:48px}md-bottom-sheet.md-grid{padding-left:24px;padding-right:24px;padding-top:0}md-bottom-sheet.md-grid md-list{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:horizontal;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap}md-bottom-sheet.md-grid md-list,md-bottom-sheet.md-grid md-list-item{-webkit-box-direction:normal;-webkit-transition:all .5s;transition:all .5s;-webkit-box-align:center;-webkit-align-items:center;align-items:center}md-bottom-sheet.md-grid md-list-item{-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column;height:96px;margin-top:8px;margin-bottom:8px}@media (max-width:960px){md-bottom-sheet.md-grid md-list-item{-webkit-box-flex:1;-webkit-flex:1 1 33.33333%;flex:1 1 33.33333%;max-width:33.33333%}md-bottom-sheet.md-grid md-list-item:nth-of-type(3n+1){-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start}md-bottom-sheet.md-grid md-list-item:nth-of-type(3n){-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end}}@media (min-width:960px) and (max-width:1279px){md-bottom-sheet.md-grid md-list-item{-webkit-box-flex:1;-webkit-flex:1 1 25%;flex:1 1 25%;max-width:25%}}@media (min-width:1280px) and (max-width:1919px){md-bottom-sheet.md-grid md-list-item{-webkit-box-flex:1;-webkit-flex:1 1 16.66667%;flex:1 1 16.66667%;max-width:16.66667%}}@media (min-width:1920px){md-bottom-sheet.md-grid md-list-item{-webkit-box-flex:1;-webkit-flex:1 1 14.28571%;flex:1 1 14.28571%;max-width:14.28571%}}md-bottom-sheet.md-grid md-list-item:before{display:none}md-bottom-sheet.md-grid md-list-item .md-list-item-content{width:48px;padding-bottom:16px}md-bottom-sheet.md-grid md-list-item .md-grid-item-content,md-bottom-sheet.md-grid md-list-item .md-list-item-content{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;-webkit-box-align:center;-webkit-align-items:center;align-items:center}md-bottom-sheet.md-grid md-list-item .md-grid-item-content{border:1px solid transparent;width:80px}md-bottom-sheet.md-grid md-list-item .md-grid-text{font-weight:400;line-height:16px;font-size:13px;margin:0;white-space:nowrap;width:64px;text-align:center;text-transform:none;padding-top:8px}@media screen and (-ms-high-contrast:active){md-bottom-sheet{border:1px solid #fff}}md-backdrop{-webkit-transition:opacity .45s;transition:opacity .45s;position:absolute;top:0;bottom:0;left:0;right:0;z-index:50}md-backdrop.md-menu-backdrop{position:fixed!important;z-index:99}md-backdrop.md-select-backdrop{z-index:81;-webkit-transition-duration:0;transition-duration:0}md-backdrop.md-dialog-backdrop{z-index:79}md-backdrop.md-bottom-sheet-backdrop{z-index:69}md-backdrop.md-sidenav-backdrop{z-index:59}md-backdrop.md-click-catcher{position:absolute}md-backdrop.md-opaque{opacity:.48}md-backdrop.md-opaque.ng-enter{opacity:0}md-backdrop.md-opaque.ng-enter.md-opaque.ng-enter-active{opacity:.48}md-backdrop.md-opaque.ng-leave{opacity:.48;-webkit-transition:opacity .4s;transition:opacity .4s}md-backdrop.md-opaque.ng-leave.md-opaque.ng-leave-active{opacity:0}md-card{box-sizing:border-box;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column;margin:8px;box-shadow:0 1px 3px 0 rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12)}md-card,md-card md-card-header{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-direction:normal}md-card md-card-header{padding:16px;-webkit-box-orient:horizontal;-webkit-flex-direction:row;flex-direction:row}md-card md-card-header:first-child md-card-avatar{margin-right:12px}[dir=rtl] md-card md-card-header:first-child md-card-avatar{margin-right:auto;margin-left:12px}md-card md-card-header:last-child md-card-avatar{margin-left:12px}[dir=rtl] md-card md-card-header:last-child md-card-avatar{margin-left:auto;margin-right:12px}md-card md-card-header md-card-avatar{width:40px;height:40px}md-card md-card-header md-card-avatar .md-user-avatar,md-card md-card-header md-card-avatar md-icon{border-radius:50%}md-card md-card-header md-card-avatar md-icon{padding:8px}md-card md-card-header md-card-avatar md-icon>svg{height:inherit;width:inherit}md-card md-card-header md-card-avatar+md-card-header-text{max-height:40px}md-card md-card-header md-card-avatar+md-card-header-text .md-title{font-size:14px}md-card md-card-header md-card-header-text{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-flex:1;-webkit-flex:1;flex:1;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}md-card md-card-header md-card-header-text .md-subhead{font-size:14px}md-card>img,md-card>md-card-header img,md-card md-card-title-media img{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;width:100%;height:auto}md-card md-card-title{padding:24px 16px 16px;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}md-card md-card-title+md-card-content{padding-top:0}md-card md-card-title md-card-title-text{-webkit-box-flex:1;-webkit-flex:1;flex:1;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;display:-webkit-box;display:-webkit-flex;display:flex}md-card md-card-title md-card-title-text .md-subhead{padding-top:0;font-size:14px}md-card md-card-title md-card-title-text:only-child .md-subhead{padding-top:12px}md-card md-card-title md-card-title-media{margin-top:-8px}md-card md-card-title md-card-title-media .md-media-sm{height:80px;width:80px}md-card md-card-title md-card-title-media .md-media-md{height:112px;width:112px}md-card md-card-title md-card-title-media .md-media-lg{height:152px;width:152px}md-card md-card-content{display:block;padding:16px}md-card md-card-content>p:first-child{margin-top:0}md-card md-card-content>p:last-child{margin-bottom:0}md-card md-card-content .md-media-xl{height:240px;width:240px}md-card .md-actions,md-card md-card-actions{margin:8px}md-card .md-actions.layout-column .md-button:not(.md-icon-button),md-card md-card-actions.layout-column .md-button:not(.md-icon-button){margin:2px 0}md-card .md-actions.layout-column .md-button:not(.md-icon-button):first-of-type,md-card md-card-actions.layout-column .md-button:not(.md-icon-button):first-of-type{margin-top:0}md-card .md-actions.layout-column .md-button:not(.md-icon-button):last-of-type,md-card md-card-actions.layout-column .md-button:not(.md-icon-button):last-of-type{margin-bottom:0}md-card .md-actions.layout-column .md-button.md-icon-button,md-card md-card-actions.layout-column .md-button.md-icon-button{margin-top:6px;margin-bottom:6px}md-card .md-actions md-card-icon-actions,md-card md-card-actions md-card-icon-actions{-webkit-box-flex:1;-webkit-flex:1;flex:1;-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}md-card .md-actions:not(.layout-column) .md-button:not(.md-icon-button),md-card md-card-actions:not(.layout-column) .md-button:not(.md-icon-button){margin:0 4px}md-card .md-actions:not(.layout-column) .md-button:not(.md-icon-button):first-of-type,md-card md-card-actions:not(.layout-column) .md-button:not(.md-icon-button):first-of-type{margin-left:0}[dir=rtl] md-card .md-actions:not(.layout-column) .md-button:not(.md-icon-button):first-of-type,[dir=rtl] md-card md-card-actions:not(.layout-column) .md-button:not(.md-icon-button):first-of-type{margin-left:auto;margin-right:0}md-card .md-actions:not(.layout-column) .md-button:not(.md-icon-button):last-of-type,md-card md-card-actions:not(.layout-column) .md-button:not(.md-icon-button):last-of-type{margin-right:0}[dir=rtl] md-card .md-actions:not(.layout-column) .md-button:not(.md-icon-button):last-of-type,[dir=rtl] md-card md-card-actions:not(.layout-column) .md-button:not(.md-icon-button):last-of-type{margin-right:auto;margin-left:0}md-card .md-actions:not(.layout-column) .md-button.md-icon-button,md-card md-card-actions:not(.layout-column) .md-button.md-icon-button{margin-left:6px;margin-right:6px}md-card .md-actions:not(.layout-column) .md-button.md-icon-button:first-of-type,md-card md-card-actions:not(.layout-column) .md-button.md-icon-button:first-of-type{margin-left:12px}[dir=rtl] md-card .md-actions:not(.layout-column) .md-button.md-icon-button:first-of-type,[dir=rtl] md-card md-card-actions:not(.layout-column) .md-button.md-icon-button:first-of-type{margin-left:auto;margin-right:12px}md-card .md-actions:not(.layout-column) .md-button.md-icon-button:last-of-type,md-card md-card-actions:not(.layout-column) .md-button.md-icon-button:last-of-type{margin-right:12px}[dir=rtl] md-card .md-actions:not(.layout-column) .md-button.md-icon-button:last-of-type,[dir=rtl] md-card md-card-actions:not(.layout-column) .md-button.md-icon-button:last-of-type{margin-right:auto;margin-left:12px}md-card .md-actions:not(.layout-column) .md-button+md-card-icon-actions,md-card md-card-actions:not(.layout-column) .md-button+md-card-icon-actions{-webkit-box-flex:1;-webkit-flex:1;flex:1;-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}md-card md-card-footer{margin-top:auto;padding:16px}@media screen and (-ms-high-contrast:active){md-card{border:1px solid #fff}}.md-image-no-fill>img{width:auto;height:auto}.md-inline-form md-checkbox{margin:19px 0 18px}md-checkbox{box-sizing:border-box;display:inline-block;margin-bottom:16px;white-space:nowrap;cursor:pointer;outline:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;position:relative;min-width:20px;min-height:20px;margin-left:0;margin-right:16px}[dir=rtl] md-checkbox{margin-left:16px;margin-right:0}md-checkbox:last-of-type{margin-left:0;margin-right:0}md-checkbox.md-focused:not([disabled]) .md-container:before{left:-8px;top:-8px;right:-8px;bottom:-8px}md-checkbox.md-focused:not([disabled]):not(.md-checked) .md-container:before{background-color:rgba(0,0,0,.12)}md-checkbox.md-align-top-left>div.md-container{top:12px}md-checkbox .md-container{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);box-sizing:border-box;display:inline-block;width:20px;height:20px;left:0;right:auto}[dir=rtl] md-checkbox .md-container{left:auto;right:0}md-checkbox .md-container:before{box-sizing:border-box;background-color:transparent;border-radius:50%;content:"";position:absolute;display:block;height:auto;left:0;top:0;right:0;bottom:0;-webkit-transition:all .5s;transition:all .5s;width:auto}md-checkbox .md-container:after{box-sizing:border-box;content:"";position:absolute;top:-10px;right:-10px;bottom:-10px;left:-10px}md-checkbox .md-container .md-ripple-container{position:absolute;display:block;width:auto;height:auto;left:-15px;top:-15px;right:-15px;bottom:-15px}md-checkbox .md-icon{box-sizing:border-box;-webkit-transition:.24s;transition:.24s;position:absolute;top:0;left:0;width:20px;height:20px;border-width:2px;border-style:solid;border-radius:2px}md-checkbox.md-checked .md-icon{border-color:transparent}md-checkbox.md-checked .md-icon:after{box-sizing:border-box;-webkit-transform:rotate(45deg);transform:rotate(45deg);position:absolute;left:4.66667px;top:.22222px;display:table;width:6.66667px;height:13.33333px;border-width:2px;border-style:solid;border-top:0;border-left:0;content:""}md-checkbox[disabled]{cursor:default}md-checkbox.md-indeterminate .md-icon:after{box-sizing:border-box;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:table;width:12px;height:2px;border-width:2px;border-style:solid;border-top:0;border-left:0;content:""}md-checkbox .md-label{box-sizing:border-box;position:relative;display:inline-block;vertical-align:middle;white-space:normal;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;margin-left:30px;margin-right:0}[dir=rtl] md-checkbox .md-label{margin-left:0;margin-right:30px}md-content{display:block;position:relative;overflow:auto;-webkit-overflow-scrolling:touch}md-content[md-scroll-y]{overflow-y:auto;overflow-x:hidden}md-content[md-scroll-x]{overflow-x:auto;overflow-y:hidden}@media print{md-content{overflow:visible!important}}.md-contact-chips .md-chips md-chip{padding:0 25px 0 0}[dir=rtl] .md-contact-chips .md-chips md-chip{padding:0 0 0 25px}.md-contact-chips .md-chips md-chip .md-contact-avatar{float:left}[dir=rtl] .md-contact-chips .md-chips md-chip .md-contact-avatar{float:right}.md-contact-chips .md-chips md-chip .md-contact-avatar img{height:32px;border-radius:16px}.md-contact-chips .md-chips md-chip .md-contact-name{display:inline-block;height:32px;margin-left:8px}[dir=rtl] .md-contact-chips .md-chips md-chip .md-contact-name{margin-left:auto;margin-right:8px}.md-contact-suggestion{height:56px}.md-contact-suggestion img{height:40px;border-radius:20px;margin-top:8px}.md-contact-suggestion .md-contact-name{margin-left:8px;width:120px}[dir=rtl] .md-contact-suggestion .md-contact-name{margin-left:auto;margin-right:8px}.md-contact-suggestion .md-contact-email,.md-contact-suggestion .md-contact-name{display:inline-block;overflow:hidden;text-overflow:ellipsis}.md-contact-chips-suggestions li{height:100%}.md-chips{display:block;font-family:Roboto,Helvetica Neue,sans-serif;font-size:16px;padding:0 0 8px 3px;vertical-align:middle}.md-chips:after{content:"";display:table;clear:both}[dir=rtl] .md-chips{padding:0 3px 8px 0}.md-chips.md-readonly .md-chip-input-container{min-height:32px}.md-chips:not(.md-readonly){cursor:text}.md-chips.md-removable md-chip{padding-right:22px}[dir=rtl] .md-chips.md-removable md-chip{padding-right:0;padding-left:22px}.md-chips.md-removable md-chip .md-chip-content{padding-right:4px}[dir=rtl] .md-chips.md-removable md-chip .md-chip-content{padding-right:0;padding-left:4px}.md-chips md-chip{cursor:default;border-radius:16px;display:block;height:32px;line-height:32px;margin:8px 8px 0 0;padding:0 12px;float:left;box-sizing:border-box;max-width:100%;position:relative}[dir=rtl] .md-chips md-chip{margin:8px 0 0 8px;float:right}.md-chips md-chip .md-chip-content{display:block;float:left;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}[dir=rtl] .md-chips md-chip .md-chip-content{float:right}.md-chips md-chip .md-chip-content:focus{outline:none}.md-chips md-chip._md-chip-content-edit-is-enabled{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-ms-user-select:none}.md-chips md-chip .md-chip-remove-container{position:absolute;right:0;line-height:22px}[dir=rtl] .md-chips md-chip .md-chip-remove-container{right:auto;left:0}.md-chips md-chip .md-chip-remove{text-align:center;width:32px;height:32px;min-width:0;padding:0;background:transparent;border:none;box-shadow:none;margin:0;position:relative}.md-chips md-chip .md-chip-remove md-icon{height:18px;width:18px;position:absolute;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.md-chips .md-chip-input-container{display:block;line-height:32px;margin:8px 8px 0 0;padding:0;float:left}[dir=rtl] .md-chips .md-chip-input-container{margin:8px 0 0 8px;float:right}.md-chips .md-chip-input-container input:not([type]),.md-chips .md-chip-input-container input[type=email],.md-chips .md-chip-input-container input[type=number],.md-chips .md-chip-input-container input[type=tel],.md-chips .md-chip-input-container input[type=text],.md-chips .md-chip-input-container input[type=url]{border:0;height:32px;line-height:32px;padding:0}.md-chips .md-chip-input-container input:not([type]):focus,.md-chips .md-chip-input-container input[type=email]:focus,.md-chips .md-chip-input-container input[type=number]:focus,.md-chips .md-chip-input-container input[type=tel]:focus,.md-chips .md-chip-input-container input[type=text]:focus,.md-chips .md-chip-input-container input[type=url]:focus{outline:none}.md-chips .md-chip-input-container md-autocomplete,.md-chips .md-chip-input-container md-autocomplete-wrap{background:transparent;height:32px}.md-chips .md-chip-input-container md-autocomplete md-autocomplete-wrap{box-shadow:none}.md-chips .md-chip-input-container input{border:0;height:32px;line-height:32px;padding:0}.md-chips .md-chip-input-container input:focus{outline:none}.md-chips .md-chip-input-container md-autocomplete,.md-chips .md-chip-input-container md-autocomplete-wrap{height:32px}.md-chips .md-chip-input-container md-autocomplete{box-shadow:none}.md-chips .md-chip-input-container md-autocomplete input{position:relative}.md-chips .md-chip-input-container:not(:first-child){margin:8px 8px 0 0}[dir=rtl] .md-chips .md-chip-input-container:not(:first-child){margin:8px 0 0 8px}.md-chips .md-chip-input-container input{background:transparent;border-width:0}.md-chips md-autocomplete button{display:none}@media screen and (-ms-high-contrast:active){.md-chip-input-container,md-chip{border:1px solid #fff}.md-chip-input-container md-autocomplete{border:none}}.md-dialog-is-showing{max-height:100%}.md-dialog-container{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;align-items:center;position:absolute;top:0;left:0;width:100%;height:100%;z-index:80;overflow:hidden}.md-dialog-container,md-dialog{display:-webkit-box;display:-webkit-flex;display:flex}md-dialog{opacity:0;min-width:240px;max-width:80%;max-height:80%;position:relative;overflow:auto;box-shadow:0 7px 8px -4px rgba(0,0,0,.2),0 13px 19px 2px rgba(0,0,0,.14),0 5px 24px 4px rgba(0,0,0,.12);-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}md-dialog.md-transition-in{opacity:1;-webkit-transform:translate(0,0) scale(1);transform:translate(0,0) scale(1)}md-dialog.md-transition-in,md-dialog.md-transition-out{-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1)}md-dialog.md-transition-out{opacity:0;-webkit-transform:translate(0,100%) scale(.2);transform:translate(0,100%) scale(.2)}md-dialog>form{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;overflow:auto}md-dialog .md-dialog-content{padding:24px}md-dialog md-dialog-content{-webkit-box-ordinal-group:2;-webkit-order:1;order:1;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;overflow:auto;-webkit-overflow-scrolling:touch}md-dialog md-dialog-content:not([layout=row])>:first-child:not(.md-subheader){margin-top:0}md-dialog md-dialog-content:focus{outline:none}md-dialog md-dialog-content .md-subheader{margin:0}md-dialog md-dialog-content .md-dialog-content-body{width:100%}md-dialog md-dialog-content .md-prompt-input-container{width:100%;box-sizing:border-box}md-dialog .md-actions,md-dialog md-dialog-actions{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-ordinal-group:3;-webkit-order:2;order:2;box-sizing:border-box;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end;margin-bottom:0;padding-right:8px;padding-left:16px;min-height:52px;overflow:hidden}[dir=rtl] md-dialog .md-actions,[dir=rtl] md-dialog md-dialog-actions{padding-right:16px;padding-left:8px}md-dialog .md-actions .md-button,md-dialog md-dialog-actions .md-button{margin:8px 0 8px 8px}[dir=rtl] md-dialog .md-actions .md-button,[dir=rtl] md-dialog md-dialog-actions .md-button{margin-left:0;margin-right:8px}md-dialog.md-content-overflow .md-actions,md-dialog.md-content-overflow md-dialog-actions{border-top-width:1px;border-top-style:solid}@media screen and (-ms-high-contrast:active){md-dialog{border:1px solid #fff}}@media (max-width:959px){md-dialog.md-dialog-fullscreen{min-height:100%;min-width:100%;border-radius:0}}md-divider{display:block;border-top-width:1px;border-top-style:solid;margin:0}md-divider[md-inset]{margin-left:80px}[dir=rtl] md-divider[md-inset]{margin-left:auto;margin-right:80px}.layout-gt-lg-row>md-divider,.layout-gt-md-row>md-divider,.layout-gt-sm-row>md-divider,.layout-gt-xs-row>md-divider,.layout-lg-row>md-divider,.layout-md-row>md-divider,.layout-row>md-divider,.layout-sm-row>md-divider,.layout-xl-row>md-divider,.layout-xs-row>md-divider{border-top-width:0;border-right-width:1px;border-right-style:solid}md-calendar{font-size:13px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.md-calendar-scroll-mask{display:inline-block;overflow:hidden;height:308px}.md-calendar-scroll-mask .md-virtual-repeat-scroller{overflow-y:scroll;-webkit-overflow-scrolling:touch}.md-calendar-scroll-mask .md-virtual-repeat-scroller::-webkit-scrollbar{display:none}.md-calendar-scroll-mask .md-virtual-repeat-offsetter{width:100%}.md-calendar-scroll-container{box-shadow:inset -3px 3px 6px rgba(0,0,0,.2);display:inline-block;height:308px;width:346px}.md-calendar-date{height:44px;width:44px;text-align:center;padding:0;border:none;box-sizing:content-box}.md-calendar-date:first-child{padding-left:16px}[dir=rtl] .md-calendar-date:first-child{padding-left:0;padding-right:16px}.md-calendar-date:last-child{padding-right:16px}[dir=rtl] .md-calendar-date:last-child{padding-right:0;padding-left:16px}.md-calendar-date.md-calendar-date-disabled{cursor:default}.md-calendar-date-selection-indicator{-webkit-transition:background-color,color .4s cubic-bezier(.25,.8,.25,1);transition:background-color,color .4s cubic-bezier(.25,.8,.25,1);border-radius:50%;display:inline-block;width:40px;height:40px;line-height:40px}.md-calendar-date:not(.md-disabled) .md-calendar-date-selection-indicator{cursor:pointer}.md-calendar-month-label{height:44px;font-size:14px;font-weight:500;padding:0 0 0 24px}[dir=rtl] .md-calendar-month-label{padding:0 24px 0 0}md-calendar-month .md-calendar-month-label:not(.md-calendar-month-label-disabled){cursor:pointer}.md-calendar-month-label md-icon{-webkit-transform:rotate(180deg);transform:rotate(180deg)}[dir=rtl] .md-calendar-month-label md-icon{-webkit-transform:none;transform:none}.md-calendar-month-label span{vertical-align:middle}.md-calendar-day-header{table-layout:fixed;border-spacing:0;border-collapse:collapse}.md-calendar-day-header th{height:40px;width:44px;text-align:center;padding:0;border:none;box-sizing:content-box;font-weight:400}.md-calendar-day-header th:first-child{padding-left:16px}[dir=rtl] .md-calendar-day-header th:first-child{padding-left:0;padding-right:16px}.md-calendar-day-header th:last-child{padding-right:16px}[dir=rtl] .md-calendar-day-header th:last-child{padding-right:0;padding-left:16px}.md-calendar{table-layout:fixed;border-spacing:0;border-collapse:collapse}.md-calendar tr:last-child td{border-bottom-width:1px;border-bottom-style:solid}.md-calendar:first-child{border-top:1px solid transparent}.md-calendar tbody,.md-calendar td,.md-calendar tr{vertical-align:middle;box-sizing:content-box}md-datepicker{white-space:nowrap;overflow:hidden;vertical-align:middle}.md-inline-form md-datepicker{margin-top:12px}.md-datepicker-button{display:inline-block;box-sizing:border-box;background:none;vertical-align:middle;position:relative}.md-datepicker-button:before{top:0;left:0;bottom:0;right:0;position:absolute;content:"";speak:none}.md-datepicker-input{font-size:14px;box-sizing:border-box;border:none;box-shadow:none;outline:none;background:transparent;min-width:120px;max-width:328px;padding:0 0 5px}.md-datepicker-input::-ms-clear{display:none}._md-datepicker-floating-label>md-datepicker{overflow:visible}._md-datepicker-floating-label>md-datepicker .md-datepicker-input-container{border:none}._md-datepicker-floating-label>md-datepicker .md-datepicker-button{float:left;margin-top:-12px;top:9.5px}[dir=rtl] ._md-datepicker-floating-label>md-datepicker .md-datepicker-button{float:right}._md-datepicker-floating-label .md-input{float:none}._md-datepicker-floating-label._md-datepicker-has-calendar-icon>label:not(.md-no-float):not(.md-container-ignore){right:18px;left:auto;width:calc(100% - 84px)}[dir=rtl] ._md-datepicker-floating-label._md-datepicker-has-calendar-icon>label:not(.md-no-float):not(.md-container-ignore){right:auto;left:18px}._md-datepicker-floating-label._md-datepicker-has-calendar-icon .md-input-message-animation{margin-left:64px}[dir=rtl] ._md-datepicker-floating-label._md-datepicker-has-calendar-icon .md-input-message-animation{margin-left:auto;margin-right:64px}._md-datepicker-has-triangle-icon{padding-right:18px;margin-right:-18px}[dir=rtl] ._md-datepicker-has-triangle-icon{padding-right:0;padding-left:18px;margin-right:auto;margin-left:-18px}.md-datepicker-input-container{position:relative;border-bottom-width:1px;border-bottom-style:solid;display:inline-block;width:auto}.md-icon-button+.md-datepicker-input-container{margin-left:12px}[dir=rtl] .md-icon-button+.md-datepicker-input-container{margin-left:auto;margin-right:12px}.md-datepicker-input-container.md-datepicker-focused{border-bottom-width:2px}.md-datepicker-is-showing .md-scroll-mask{z-index:99}.md-datepicker-calendar-pane{position:absolute;top:0;left:-100%;z-index:100;border-width:1px;border-style:solid;background:transparent;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transition:-webkit-transform .2s cubic-bezier(.25,.8,.25,1);transition:-webkit-transform .2s cubic-bezier(.25,.8,.25,1);transition:transform .2s cubic-bezier(.25,.8,.25,1);transition:transform .2s cubic-bezier(.25,.8,.25,1),-webkit-transform .2s cubic-bezier(.25,.8,.25,1)}.md-datepicker-calendar-pane.md-pane-open{-webkit-transform:scale(1);transform:scale(1)}.md-datepicker-input-mask{height:40px;width:340px;position:relative;overflow:hidden;background:transparent;pointer-events:none;cursor:text}.md-datepicker-calendar{opacity:0;-webkit-transition:opacity .2s cubic-bezier(.5,0,.25,1);transition:opacity .2s cubic-bezier(.5,0,.25,1)}.md-pane-open .md-datepicker-calendar{opacity:1}.md-datepicker-calendar md-calendar:focus{outline:none}.md-datepicker-expand-triangle{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid}.md-datepicker-triangle-button{position:absolute;right:0;bottom:-2.5px;-webkit-transform:translateX(45%);transform:translateX(45%)}[dir=rtl] .md-datepicker-triangle-button{right:auto;left:0;-webkit-transform:translateX(-45%);transform:translateX(-45%)}.md-datepicker-triangle-button.md-button.md-icon-button{height:36px;width:36px;position:absolute;padding:8px}md-datepicker[disabled] .md-datepicker-input-container{border-bottom-color:transparent}md-datepicker[disabled] .md-datepicker-triangle-button{display:none}.md-datepicker-open{overflow:hidden}.md-datepicker-open .md-datepicker-input-container,.md-datepicker-open input.md-input{border-bottom-color:transparent}.md-datepicker-open .md-datepicker-triangle-button,.md-datepicker-open.md-input-has-placeholder>label,.md-datepicker-open.md-input-has-value>label,.md-datepicker-pos-adjusted .md-datepicker-input-mask{display:none}.md-datepicker-calendar-pane .md-calendar{-webkit-transform:translateY(-85px);transform:translateY(-85px);-webkit-transition:-webkit-transform .65s cubic-bezier(.25,.8,.25,1);transition:-webkit-transform .65s cubic-bezier(.25,.8,.25,1);transition:transform .65s cubic-bezier(.25,.8,.25,1);transition:transform .65s cubic-bezier(.25,.8,.25,1),-webkit-transform .65s cubic-bezier(.25,.8,.25,1);-webkit-transition-delay:.125s;transition-delay:.125s}.md-datepicker-calendar-pane.md-pane-open .md-calendar{-webkit-transform:translateY(0);transform:translateY(0)}md-fab-toolbar{display:block}md-fab-toolbar.md-fab-bottom-right{top:auto;right:20px;bottom:20px;left:auto;position:absolute}md-fab-toolbar.md-fab-bottom-left{top:auto;right:auto;bottom:20px;left:20px;position:absolute}md-fab-toolbar.md-fab-top-right{top:20px;right:20px;bottom:auto;left:auto;position:absolute}md-fab-toolbar.md-fab-top-left{top:20px;right:auto;bottom:auto;left:20px;position:absolute}md-fab-toolbar .md-fab-toolbar-wrapper{display:block;position:relative;overflow:hidden;height:68px}md-fab-toolbar md-fab-trigger{position:absolute;z-index:20}md-fab-toolbar md-fab-trigger button{overflow:visible!important}md-fab-toolbar md-fab-trigger .md-fab-toolbar-background{display:block;position:absolute;z-index:21;opacity:1;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2)}md-fab-toolbar md-fab-trigger md-icon{position:relative;z-index:22;opacity:1;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}md-fab-toolbar.md-left md-fab-trigger{right:0}[dir=rtl] md-fab-toolbar.md-left md-fab-trigger{right:auto;left:0}md-fab-toolbar.md-left .md-toolbar-tools{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-webkit-flex-direction:row-reverse;flex-direction:row-reverse}md-fab-toolbar.md-left .md-toolbar-tools>.md-button:first-child{margin-right:.6rem}[dir=rtl] md-fab-toolbar.md-left .md-toolbar-tools>.md-button:first-child{margin-right:auto;margin-left:.6rem}md-fab-toolbar.md-left .md-toolbar-tools>.md-button:first-child{margin-left:-.8rem}[dir=rtl] md-fab-toolbar.md-left .md-toolbar-tools>.md-button:first-child{margin-left:auto;margin-right:-.8rem}md-fab-toolbar.md-left .md-toolbar-tools>.md-button:last-child{margin-right:8px}[dir=rtl] md-fab-toolbar.md-left .md-toolbar-tools>.md-button:last-child{margin-right:auto;margin-left:8px}md-fab-toolbar.md-right md-fab-trigger{left:0}[dir=rtl] md-fab-toolbar.md-right md-fab-trigger{left:auto;right:0}md-fab-toolbar.md-right .md-toolbar-tools{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}md-fab-toolbar md-toolbar{background-color:transparent!important;pointer-events:none;z-index:23}md-fab-toolbar md-toolbar .md-toolbar-tools{padding:0 20px;margin-top:3px}md-fab-toolbar md-toolbar .md-fab-action-item{opacity:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-duration:.15s;transition-duration:.15s}md-fab-toolbar.md-is-open md-fab-trigger>button{box-shadow:none}md-fab-toolbar.md-is-open md-fab-trigger>button md-icon{opacity:0}md-fab-toolbar.md-is-open .md-fab-action-item{opacity:1;-webkit-transform:scale(1);transform:scale(1)}md-fab-speed-dial{position:relative;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;z-index:20}md-fab-speed-dial.md-fab-bottom-right{top:auto;right:20px;bottom:20px;left:auto;position:absolute}md-fab-speed-dial.md-fab-bottom-left{top:auto;right:auto;bottom:20px;left:20px;position:absolute}md-fab-speed-dial.md-fab-top-right{top:20px;right:20px;bottom:auto;left:auto;position:absolute}md-fab-speed-dial.md-fab-top-left{top:20px;right:auto;bottom:auto;left:20px;position:absolute}md-fab-speed-dial:not(.md-hover-full){pointer-events:none}md-fab-speed-dial:not(.md-hover-full) .md-fab-action-item,md-fab-speed-dial:not(.md-hover-full).md-is-open,md-fab-speed-dial:not(.md-hover-full) md-fab-trigger{pointer-events:auto}md-fab-speed-dial ._md-css-variables{z-index:20}md-fab-speed-dial.md-is-open .md-fab-action-item{-webkit-box-align:center;-webkit-align-items:center;align-items:center}md-fab-speed-dial md-fab-actions{display:-webkit-box;display:-webkit-flex;display:flex;height:auto}md-fab-speed-dial md-fab-actions .md-fab-action-item{-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2)}md-fab-speed-dial.md-down{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}md-fab-speed-dial.md-down md-fab-trigger{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}md-fab-speed-dial.md-down md-fab-actions{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;-webkit-box-ordinal-group:3;-webkit-order:2;order:2}md-fab-speed-dial.md-up{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}md-fab-speed-dial.md-up md-fab-trigger{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}md-fab-speed-dial.md-up md-fab-actions{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-webkit-flex-direction:column-reverse;flex-direction:column-reverse;-webkit-box-ordinal-group:2;-webkit-order:1;order:1}md-fab-speed-dial.md-left{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}md-fab-speed-dial.md-left md-fab-trigger{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}md-fab-speed-dial.md-left md-fab-actions{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-webkit-flex-direction:row-reverse;flex-direction:row-reverse;-webkit-box-ordinal-group:2;-webkit-order:1;order:1}md-fab-speed-dial.md-left md-fab-actions .md-fab-action-item{-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2)}md-fab-speed-dial.md-right{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}md-fab-speed-dial.md-right md-fab-trigger{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}md-fab-speed-dial.md-right md-fab-actions{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row;-webkit-box-ordinal-group:3;-webkit-order:2;order:2}md-fab-speed-dial.md-right md-fab-actions .md-fab-action-item{-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2)}md-fab-speed-dial.md-fling-remove .md-fab-action-item>*,md-fab-speed-dial.md-scale-remove .md-fab-action-item>*{visibility:hidden}md-fab-speed-dial.md-fling .md-fab-action-item{opacity:1}md-fab-speed-dial.md-fling.md-animations-waiting .md-fab-action-item{opacity:0;-webkit-transition-duration:0s;transition-duration:0s}md-fab-speed-dial.md-scale .md-fab-action-item{-webkit-transform:scale(0);transform:scale(0);-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-duration:.14286s;transition-duration:.14286s}md-grid-list{display:block;position:relative}md-grid-list,md-grid-list md-grid-tile,md-grid-list md-grid-tile-footer,md-grid-list md-grid-tile-header,md-grid-list md-grid-tile>figure{box-sizing:border-box}md-grid-list md-grid-tile{display:block;position:absolute}md-grid-list md-grid-tile figure{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;height:100%;top:0;bottom:0;padding:0;margin:0}md-grid-list md-grid-tile figure,md-grid-list md-grid-tile md-grid-tile-footer,md-grid-list md-grid-tile md-grid-tile-header{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;position:absolute;right:0;left:0}md-grid-list md-grid-tile md-grid-tile-footer,md-grid-list md-grid-tile md-grid-tile-header{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row;height:48px;color:#fff;background:rgba(0,0,0,.18);overflow:hidden}md-grid-list md-grid-tile md-grid-tile-footer h3,md-grid-list md-grid-tile md-grid-tile-footer h4,md-grid-list md-grid-tile md-grid-tile-header h3,md-grid-list md-grid-tile md-grid-tile-header h4{font-weight:400;margin:0 0 0 16px}md-grid-list md-grid-tile md-grid-tile-footer h3,md-grid-list md-grid-tile md-grid-tile-header h3{font-size:14px}md-grid-list md-grid-tile md-grid-tile-footer h4,md-grid-list md-grid-tile md-grid-tile-header h4{font-size:12px}md-grid-list md-grid-tile md-grid-tile-header{top:0}md-grid-list md-grid-tile md-grid-tile-footer{bottom:0}@media screen and (-ms-high-contrast:active){md-grid-tile{border:1px solid #fff}md-grid-tile-footer{border-top:1px solid #fff}}md-icon{margin:auto;background-repeat:no-repeat;display:inline-block;vertical-align:middle;fill:currentColor;height:24px;width:24px;min-height:24px;min-width:24px}md-icon svg{pointer-events:none;display:block}md-icon[md-font-icon]{line-height:24px;width:auto}md-input-container{display:inline-block;position:relative;padding:2px;margin:18px 0;vertical-align:middle}md-input-container:after{content:"";display:table;clear:both}md-input-container.md-block{display:block}md-input-container .md-errors-spacer{float:right;min-height:24px;min-width:1px}[dir=rtl] md-input-container .md-errors-spacer{float:left}md-input-container>md-icon{position:absolute;top:8px;left:2px;right:auto}[dir=rtl] md-input-container>md-icon{left:auto;right:2px}md-input-container input[type=color],md-input-container input[type=date],md-input-container input[type=datetime-local],md-input-container input[type=datetime],md-input-container input[type=email],md-input-container input[type=month],md-input-container input[type=number],md-input-container input[type=password],md-input-container input[type=search],md-input-container input[type=tel],md-input-container input[type=text],md-input-container input[type=time],md-input-container input[type=url],md-input-container input[type=week],md-input-container textarea{-moz-appearance:none;-webkit-appearance:none}md-input-container input[type=date],md-input-container input[type=datetime-local],md-input-container input[type=month],md-input-container input[type=time],md-input-container input[type=week]{min-height:26px}md-input-container textarea{resize:none;overflow:hidden}md-input-container textarea.md-input{min-height:26px;-ms-flex-preferred-size:auto}md-input-container textarea[md-no-autogrow]{height:auto;overflow:auto}md-input-container label:not(.md-container-ignore){position:absolute;bottom:100%;left:0;right:auto}[dir=rtl] md-input-container label:not(.md-container-ignore){left:auto;right:0}md-input-container label:not(.md-container-ignore).md-required:after{content:" *";font-size:13px;vertical-align:top}md-input-container .md-placeholder,md-input-container label:not(.md-no-float):not(.md-container-ignore){overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%;-webkit-box-ordinal-group:2;-webkit-order:1;order:1;pointer-events:none;-webkit-font-smoothing:antialiased;padding-left:3px;padding-right:0;z-index:1;-webkit-transform:translate3d(0,28px,0) scale(1);transform:translate3d(0,28px,0) scale(1);-webkit-transition:-webkit-transform .4s cubic-bezier(.25,.8,.25,1);transition:-webkit-transform .4s cubic-bezier(.25,.8,.25,1);transition:transform .4s cubic-bezier(.25,.8,.25,1);transition:transform .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);max-width:100%;-webkit-transform-origin:left top;transform-origin:left top}[dir=rtl] md-input-container .md-placeholder,[dir=rtl] md-input-container label:not(.md-no-float):not(.md-container-ignore){padding-left:0;padding-right:3px;-webkit-transform-origin:right top;transform-origin:right top}md-input-container .md-placeholder{position:absolute;top:0;opacity:0;-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform;-webkit-transform:translate3d(0,30px,0);transform:translate3d(0,30px,0)}md-input-container.md-input-focused .md-placeholder{opacity:1;-webkit-transform:translate3d(0,24px,0);transform:translate3d(0,24px,0)}md-input-container.md-input-has-value .md-placeholder{-webkit-transition:none;transition:none;opacity:0}md-input-container:not(.md-input-has-value) input:not(:focus),md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-ampm-field,md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-day-field,md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-hour-field,md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-millisecond-field,md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-minute-field,md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-month-field,md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-second-field,md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-text,md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-week-field,md-input-container:not(.md-input-has-value) input:not(:focus)::-webkit-datetime-edit-year-field{color:transparent}md-input-container .md-input{-webkit-box-ordinal-group:3;-webkit-order:2;order:2;display:block;margin-top:0;background:none;padding:2px 2px 1px;border-width:0 0 1px;line-height:26px;height:30px;-ms-flex-preferred-size:26px;border-radius:0;border-style:solid;width:100%;box-sizing:border-box;float:left}[dir=rtl] md-input-container .md-input{float:right}md-input-container .md-input:focus{outline:none}md-input-container .md-input:invalid{outline:none;box-shadow:none}md-input-container .md-input.md-no-flex{-webkit-box-flex:0!important;-webkit-flex:none!important;flex:none!important}md-input-container .md-char-counter{text-align:right;padding-right:2px;padding-left:0}[dir=rtl] md-input-container .md-char-counter{text-align:left;padding-right:0;padding-left:2px}md-input-container .md-input-messages-animation{position:relative;-webkit-box-ordinal-group:5;-webkit-order:4;order:4;overflow:hidden;clear:left}[dir=rtl] md-input-container .md-input-messages-animation{clear:right}md-input-container .md-input-messages-animation.ng-enter .md-input-message-animation{opacity:0;margin-top:-100px}md-input-container .md-char-counter,md-input-container .md-input-message-animation{font-size:12px;line-height:14px;overflow:hidden;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);opacity:1;margin-top:0;padding-top:5px}md-input-container .md-char-counter:not(.md-char-counter),md-input-container .md-input-message-animation:not(.md-char-counter){padding-right:5px;padding-left:0}[dir=rtl] md-input-container .md-char-counter:not(.md-char-counter),[dir=rtl] md-input-container .md-input-message-animation:not(.md-char-counter){padding-right:0;padding-left:5px}md-input-container .md-input-message-animation.ng-enter,md-input-container .md-input-message-animation:not(.ng-animate),md-input-container:not(.md-input-invalid) .md-auto-hide .md-input-message-animation{opacity:0;margin-top:-100px}md-input-container.md-input-focused label:not(.md-no-float),md-input-container.md-input-has-placeholder label:not(.md-no-float),md-input-container.md-input-has-value label:not(.md-no-float){-webkit-transform:translate3d(0,6px,0) scale(.75);transform:translate3d(0,6px,0) scale(.75);-webkit-transition:width .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);transition:width .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);transition:transform .4s cubic-bezier(.25,.8,.25,1),width .4s cubic-bezier(.25,.8,.25,1);transition:transform .4s cubic-bezier(.25,.8,.25,1),width .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1)}md-input-container.md-input-has-value label{-webkit-transition:none;transition:none}md-input-container.md-input-focused .md-input,md-input-container.md-input-resized .md-input,md-input-container .md-input.ng-invalid.ng-dirty{padding-bottom:0;border-width:0 0 2px}[disabled] md-input-container .md-input,md-input-container .md-input[disabled]{background-position:bottom -1px left 0;background-size:4px 1px;background-repeat:repeat-x}md-input-container.md-icon-float{-webkit-transition:margin-top .4s cubic-bezier(.25,.8,.25,1);transition:margin-top .4s cubic-bezier(.25,.8,.25,1)}md-input-container.md-icon-float>label{pointer-events:none;position:absolute}md-input-container.md-icon-float>md-icon{top:8px;left:2px;right:auto}[dir=rtl] md-input-container.md-icon-float>md-icon{left:auto;right:2px}md-input-container.md-icon-left>label .md-placeholder,md-input-container.md-icon-left>label:not(.md-no-float):not(.md-container-ignore),md-input-container.md-icon-right>label .md-placeholder,md-input-container.md-icon-right>label:not(.md-no-float):not(.md-container-ignore){width:calc(100% - 36px - 18px)}md-input-container.md-icon-left{padding-left:36px;padding-right:0}[dir=rtl] md-input-container.md-icon-left{padding-left:0;padding-right:36px}md-input-container.md-icon-left>label{left:36px;right:auto}[dir=rtl] md-input-container.md-icon-left>label{left:auto;right:36px}md-input-container.md-icon-right{padding-left:0;padding-right:36px}[dir=rtl] md-input-container.md-icon-right{padding-left:36px;padding-right:0}md-input-container.md-icon-right>md-icon:last-of-type{margin:0;right:2px;left:auto}[dir=rtl] md-input-container.md-icon-right>md-icon:last-of-type{right:auto;left:2px}md-input-container.md-icon-left.md-icon-right{padding-left:36px;padding-right:36px}md-input-container.md-icon-left.md-icon-right>label .md-placeholder,md-input-container.md-icon-left.md-icon-right>label:not(.md-no-float):not(.md-container-ignore){width:calc(100% - 72px)}.md-resize-wrapper{position:relative}.md-resize-wrapper:after{content:"";display:table;clear:both}.md-resize-handle{position:absolute;bottom:-5px;left:0;height:10px;background:transparent;width:100%;cursor:ns-resize}@media screen and (-ms-high-contrast:active){md-input-container.md-default-theme>md-icon{fill:#fff}}md-list{display:block;padding:8px 0}md-list .md-subheader{font-size:14px;font-weight:500;letter-spacing:.01em;line-height:1.2em}md-list.md-dense md-list-item,md-list.md-dense md-list-item .md-list-item-inner{min-height:48px}md-list.md-dense md-list-item .md-list-item-inner:before,md-list.md-dense md-list-item:before{content:"";min-height:48px;visibility:hidden;display:inline-block}md-list.md-dense md-list-item .md-list-item-inner md-icon:first-child,md-list.md-dense md-list-item md-icon:first-child{width:20px;height:20px}md-list.md-dense md-list-item .md-list-item-inner>md-icon:first-child:not(.md-avatar-icon),md-list.md-dense md-list-item>md-icon:first-child:not(.md-avatar-icon){margin-right:36px}[dir=rtl] md-list.md-dense md-list-item .md-list-item-inner>md-icon:first-child:not(.md-avatar-icon),[dir=rtl] md-list.md-dense md-list-item>md-icon:first-child:not(.md-avatar-icon){margin-right:auto;margin-left:36px}md-list.md-dense md-list-item .md-avatar,md-list.md-dense md-list-item .md-avatar-icon,md-list.md-dense md-list-item .md-list-item-inner .md-avatar,md-list.md-dense md-list-item .md-list-item-inner .md-avatar-icon{margin-right:20px}[dir=rtl] md-list.md-dense md-list-item .md-avatar,[dir=rtl] md-list.md-dense md-list-item .md-avatar-icon,[dir=rtl] md-list.md-dense md-list-item .md-list-item-inner .md-avatar,[dir=rtl] md-list.md-dense md-list-item .md-list-item-inner .md-avatar-icon{margin-right:auto;margin-left:20px}md-list.md-dense md-list-item .md-avatar,md-list.md-dense md-list-item .md-list-item-inner .md-avatar{-webkit-box-flex:0;-webkit-flex:none;flex:none;width:36px;height:36px}md-list.md-dense md-list-item.md-2-line .md-list-item-text.md-offset,md-list.md-dense md-list-item.md-2-line>.md-no-style .md-list-item-text.md-offset,md-list.md-dense md-list-item.md-3-line .md-list-item-text.md-offset,md-list.md-dense md-list-item.md-3-line>.md-no-style .md-list-item-text.md-offset{margin-left:56px}[dir=rtl] md-list.md-dense md-list-item.md-2-line .md-list-item-text.md-offset,[dir=rtl] md-list.md-dense md-list-item.md-2-line>.md-no-style .md-list-item-text.md-offset,[dir=rtl] md-list.md-dense md-list-item.md-3-line .md-list-item-text.md-offset,[dir=rtl] md-list.md-dense md-list-item.md-3-line>.md-no-style .md-list-item-text.md-offset{margin-left:auto;margin-right:56px}md-list.md-dense md-list-item.md-2-line .md-list-item-text h3,md-list.md-dense md-list-item.md-2-line .md-list-item-text h4,md-list.md-dense md-list-item.md-2-line .md-list-item-text p,md-list.md-dense md-list-item.md-2-line>.md-no-style .md-list-item-text h3,md-list.md-dense md-list-item.md-2-line>.md-no-style .md-list-item-text h4,md-list.md-dense md-list-item.md-2-line>.md-no-style .md-list-item-text p,md-list.md-dense md-list-item.md-3-line .md-list-item-text h3,md-list.md-dense md-list-item.md-3-line .md-list-item-text h4,md-list.md-dense md-list-item.md-3-line .md-list-item-text p,md-list.md-dense md-list-item.md-3-line>.md-no-style .md-list-item-text h3,md-list.md-dense md-list-item.md-3-line>.md-no-style .md-list-item-text h4,md-list.md-dense md-list-item.md-3-line>.md-no-style .md-list-item-text p{line-height:1.05;font-size:12px}md-list.md-dense md-list-item.md-2-line .md-list-item-text h3,md-list.md-dense md-list-item.md-2-line>.md-no-style .md-list-item-text h3,md-list.md-dense md-list-item.md-3-line .md-list-item-text h3,md-list.md-dense md-list-item.md-3-line>.md-no-style .md-list-item-text h3{font-size:13px}md-list.md-dense md-list-item.md-2-line,md-list.md-dense md-list-item.md-2-line>.md-no-style{min-height:60px}md-list.md-dense md-list-item.md-2-line:before,md-list.md-dense md-list-item.md-2-line>.md-no-style:before{content:"";min-height:60px;visibility:hidden;display:inline-block}md-list.md-dense md-list-item.md-2-line .md-avatar-icon,md-list.md-dense md-list-item.md-2-line>.md-avatar,md-list.md-dense md-list-item.md-2-line>.md-no-style .md-avatar-icon,md-list.md-dense md-list-item.md-2-line>.md-no-style>.md-avatar{margin-top:12px}md-list.md-dense md-list-item.md-3-line,md-list.md-dense md-list-item.md-3-line>.md-no-style{min-height:76px}md-list.md-dense md-list-item.md-3-line:before,md-list.md-dense md-list-item.md-3-line>.md-no-style:before{content:"";min-height:76px;visibility:hidden;display:inline-block}md-list.md-dense md-list-item.md-3-line>.md-avatar,md-list.md-dense md-list-item.md-3-line>.md-no-style>.md-avatar,md-list.md-dense md-list-item.md-3-line>.md-no-style>md-icon:first-child,md-list.md-dense md-list-item.md-3-line>md-icon:first-child{margin-top:16px}md-list-item{position:relative}md-list-item.md-proxy-focus.md-focused .md-no-style{-webkit-transition:background-color .15s linear;transition:background-color .15s linear}md-list-item._md-button-wrap{position:relative}md-list-item._md-button-wrap>div.md-button:first-child{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;padding:0 16px;margin:0;font-weight:400;text-align:left;border:medium none}[dir=rtl] md-list-item._md-button-wrap>div.md-button:first-child{text-align:right}md-list-item._md-button-wrap>div.md-button:first-child>.md-button:first-child{position:absolute;top:0;left:0;height:100%;margin:0;padding:0}md-list-item._md-button-wrap>div.md-button:first-child .md-list-item-inner{width:100%;min-height:inherit}md-list-item.md-no-proxy,md-list-item .md-no-style{position:relative;padding:0 16px;-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto}md-list-item.md-no-proxy.md-button,md-list-item .md-no-style.md-button{font-size:inherit;height:inherit;text-align:left;text-transform:none;width:100%;white-space:normal;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:inherit;flex-direction:inherit;-webkit-box-align:inherit;-webkit-align-items:inherit;align-items:inherit;border-radius:0;margin:0}[dir=rtl] md-list-item.md-no-proxy.md-button,[dir=rtl] md-list-item .md-no-style.md-button{text-align:right}md-list-item.md-no-proxy.md-button>.md-ripple-container,md-list-item .md-no-style.md-button>.md-ripple-container{border-radius:0}md-list-item.md-no-proxy:focus,md-list-item .md-no-style:focus{outline:none}md-list-item.md-clickable:hover{cursor:pointer}md-list-item md-divider{position:absolute;bottom:0;left:0;width:100%}[dir=rtl] md-list-item md-divider{left:auto;right:0}md-list-item md-divider[md-inset]{left:72px;width:calc(100% - 72px);margin:0!important}[dir=rtl] md-list-item md-divider[md-inset]{left:auto;right:72px}md-list-item,md-list-item .md-list-item-inner{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;-webkit-box-align:center;-webkit-align-items:center;align-items:center;min-height:48px;height:auto}md-list-item .md-list-item-inner:before,md-list-item:before{content:"";min-height:48px;visibility:hidden;display:inline-block}md-list-item .md-list-item-inner>div.md-primary>md-icon:not(.md-avatar-icon),md-list-item .md-list-item-inner>div.md-secondary>md-icon:not(.md-avatar-icon),md-list-item .md-list-item-inner>md-icon.md-secondary:not(.md-avatar-icon),md-list-item .md-list-item-inner>md-icon:first-child:not(.md-avatar-icon),md-list-item>div.md-primary>md-icon:not(.md-avatar-icon),md-list-item>div.md-secondary>md-icon:not(.md-avatar-icon),md-list-item>md-icon.md-secondary:not(.md-avatar-icon),md-list-item>md-icon:first-child:not(.md-avatar-icon){width:24px;margin-top:16px;margin-bottom:12px;box-sizing:content-box}md-list-item .md-list-item-inner>div.md-primary>md-checkbox,md-list-item .md-list-item-inner>div.md-secondary>md-checkbox,md-list-item .md-list-item-inner>md-checkbox,md-list-item .md-list-item-inner md-checkbox.md-secondary,md-list-item>div.md-primary>md-checkbox,md-list-item>div.md-secondary>md-checkbox,md-list-item>md-checkbox,md-list-item md-checkbox.md-secondary{-webkit-align-self:center;-ms-grid-row-align:center;align-self:center}md-list-item .md-list-item-inner>div.md-primary>md-checkbox .md-label,md-list-item .md-list-item-inner>div.md-secondary>md-checkbox .md-label,md-list-item .md-list-item-inner>md-checkbox .md-label,md-list-item .md-list-item-inner md-checkbox.md-secondary .md-label,md-list-item>div.md-primary>md-checkbox .md-label,md-list-item>div.md-secondary>md-checkbox .md-label,md-list-item>md-checkbox .md-label,md-list-item md-checkbox.md-secondary .md-label{display:none}md-list-item .md-list-item-inner>md-icon:first-child:not(.md-avatar-icon),md-list-item>md-icon:first-child:not(.md-avatar-icon){margin-right:32px}[dir=rtl] md-list-item .md-list-item-inner>md-icon:first-child:not(.md-avatar-icon),[dir=rtl] md-list-item>md-icon:first-child:not(.md-avatar-icon){margin-right:auto;margin-left:32px}md-list-item .md-avatar,md-list-item .md-avatar-icon,md-list-item .md-list-item-inner .md-avatar,md-list-item .md-list-item-inner .md-avatar-icon{margin-top:8px;margin-bottom:8px;margin-right:16px;border-radius:50%;box-sizing:content-box}[dir=rtl] md-list-item .md-avatar,[dir=rtl] md-list-item .md-avatar-icon,[dir=rtl] md-list-item .md-list-item-inner .md-avatar,[dir=rtl] md-list-item .md-list-item-inner .md-avatar-icon{margin-right:auto;margin-left:16px}md-list-item .md-avatar,md-list-item .md-list-item-inner .md-avatar{-webkit-box-flex:0;-webkit-flex:none;flex:none;width:40px;height:40px}md-list-item .md-avatar-icon,md-list-item .md-list-item-inner .md-avatar-icon{padding:8px}md-list-item .md-avatar-icon svg,md-list-item .md-list-item-inner .md-avatar-icon svg{width:24px;height:24px}md-list-item .md-list-item-inner>md-checkbox,md-list-item>md-checkbox{width:24px;margin-left:3px;margin-right:29px;margin-top:16px}[dir=rtl] md-list-item .md-list-item-inner>md-checkbox,[dir=rtl] md-list-item>md-checkbox{margin-left:29px;margin-right:3px}md-list-item .md-list-item-inner .md-secondary-container,md-list-item .md-secondary-container{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-flex-shrink:0;flex-shrink:0;margin:auto;margin-right:0;margin-left:auto}[dir=rtl] md-list-item .md-list-item-inner .md-secondary-container,[dir=rtl] md-list-item .md-secondary-container{margin-right:auto;margin-left:0}md-list-item .md-list-item-inner .md-secondary-container .md-button:last-of-type,md-list-item .md-list-item-inner .md-secondary-container .md-icon-button:last-of-type,md-list-item .md-secondary-container .md-button:last-of-type,md-list-item .md-secondary-container .md-icon-button:last-of-type{margin-right:0}[dir=rtl] md-list-item .md-list-item-inner .md-secondary-container .md-button:last-of-type,[dir=rtl] md-list-item .md-list-item-inner .md-secondary-container .md-icon-button:last-of-type,[dir=rtl] md-list-item .md-secondary-container .md-button:last-of-type,[dir=rtl] md-list-item .md-secondary-container .md-icon-button:last-of-type{margin-right:auto;margin-left:0}md-list-item .md-list-item-inner .md-secondary-container md-checkbox,md-list-item .md-secondary-container md-checkbox{margin-top:0;margin-bottom:0}md-list-item .md-list-item-inner .md-secondary-container md-checkbox:last-child,md-list-item .md-secondary-container md-checkbox:last-child{width:24px;margin-right:0}[dir=rtl] md-list-item .md-list-item-inner .md-secondary-container md-checkbox:last-child,[dir=rtl] md-list-item .md-secondary-container md-checkbox:last-child{margin-right:auto;margin-left:0}md-list-item .md-list-item-inner .md-secondary-container md-switch,md-list-item .md-secondary-container md-switch{margin-top:0;margin-bottom:0;margin-right:-6px}[dir=rtl] md-list-item .md-list-item-inner .md-secondary-container md-switch,[dir=rtl] md-list-item .md-secondary-container md-switch{margin-right:auto;margin-left:-6px}md-list-item .md-list-item-inner>.md-list-item-inner>p,md-list-item .md-list-item-inner>p,md-list-item>.md-list-item-inner>p,md-list-item>p{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;margin:0}md-list-item.md-2-line,md-list-item.md-2-line>.md-no-style,md-list-item.md-3-line,md-list-item.md-3-line>.md-no-style{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}md-list-item.md-2-line.md-long-text,md-list-item.md-2-line>.md-no-style.md-long-text,md-list-item.md-3-line.md-long-text,md-list-item.md-3-line>.md-no-style.md-long-text{margin-top:8px;margin-bottom:8px}md-list-item.md-2-line .md-list-item-text,md-list-item.md-2-line>.md-no-style .md-list-item-text,md-list-item.md-3-line .md-list-item-text,md-list-item.md-3-line>.md-no-style .md-list-item-text{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;margin:auto;text-overflow:ellipsis;overflow:hidden}md-list-item.md-2-line .md-list-item-text.md-offset,md-list-item.md-2-line>.md-no-style .md-list-item-text.md-offset,md-list-item.md-3-line .md-list-item-text.md-offset,md-list-item.md-3-line>.md-no-style .md-list-item-text.md-offset{margin-left:56px}[dir=rtl] md-list-item.md-2-line .md-list-item-text.md-offset,[dir=rtl] md-list-item.md-2-line>.md-no-style .md-list-item-text.md-offset,[dir=rtl] md-list-item.md-3-line .md-list-item-text.md-offset,[dir=rtl] md-list-item.md-3-line>.md-no-style .md-list-item-text.md-offset{margin-left:auto;margin-right:56px}md-list-item.md-2-line .md-list-item-text h3,md-list-item.md-2-line>.md-no-style .md-list-item-text h3,md-list-item.md-3-line .md-list-item-text h3,md-list-item.md-3-line>.md-no-style .md-list-item-text h3{font-size:16px;font-weight:400;letter-spacing:.01em;margin:0;line-height:1.2em;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}md-list-item.md-2-line .md-list-item-text h4,md-list-item.md-2-line>.md-no-style .md-list-item-text h4,md-list-item.md-3-line .md-list-item-text h4,md-list-item.md-3-line>.md-no-style .md-list-item-text h4{font-size:14px;letter-spacing:.01em;margin:3px 0 1px;font-weight:400;line-height:1.2em;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}md-list-item.md-2-line .md-list-item-text p,md-list-item.md-2-line>.md-no-style .md-list-item-text p,md-list-item.md-3-line .md-list-item-text p,md-list-item.md-3-line>.md-no-style .md-list-item-text p{font-size:14px;font-weight:500;letter-spacing:.01em;margin:0;line-height:1.6em}md-list-item.md-2-line,md-list-item.md-2-line>.md-no-style{height:auto;min-height:72px}md-list-item.md-2-line:before,md-list-item.md-2-line>.md-no-style:before{content:"";min-height:72px;visibility:hidden;display:inline-block}md-list-item.md-2-line .md-avatar-icon,md-list-item.md-2-line>.md-avatar,md-list-item.md-2-line>.md-no-style .md-avatar-icon,md-list-item.md-2-line>.md-no-style>.md-avatar{margin-top:12px}md-list-item.md-2-line>.md-no-style>md-icon:first-child,md-list-item.md-2-line>md-icon:first-child{-webkit-align-self:flex-start;align-self:flex-start}md-list-item.md-2-line .md-list-item-text,md-list-item.md-2-line>.md-no-style .md-list-item-text{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto}md-list-item.md-3-line,md-list-item.md-3-line>.md-no-style{height:auto;min-height:88px}md-list-item.md-3-line:before,md-list-item.md-3-line>.md-no-style:before{content:"";min-height:88px;visibility:hidden;display:inline-block}md-list-item.md-3-line>.md-avatar,md-list-item.md-3-line>.md-no-style>.md-avatar,md-list-item.md-3-line>.md-no-style>md-icon:first-child,md-list-item.md-3-line>md-icon:first-child{margin-top:16px}md-toolbar.md-menu-toolbar h2.md-toolbar-tools{line-height:1rem;height:auto;padding:28px;padding-bottom:12px}md-toolbar.md-has-open-menu{position:relative;z-index:100}md-menu-bar{padding:0 20px;display:block;position:relative;z-index:2}md-menu-bar .md-menu{display:inline-block;padding:0;position:relative}md-menu-bar button{font-size:14px;padding:0 10px;margin:0;border:0;background-color:transparent;height:40px}md-menu-bar md-backdrop.md-menu-backdrop{z-index:-2}md-menu-content.md-menu-bar-menu.md-dense{max-height:none;padding:16px 0}md-menu-content.md-menu-bar-menu.md-dense md-menu-item.md-indent{position:relative}md-menu-content.md-menu-bar-menu.md-dense md-menu-item.md-indent>md-icon{position:absolute;padding:0;width:24px;top:6px;left:24px}[dir=rtl] md-menu-content.md-menu-bar-menu.md-dense md-menu-item.md-indent>md-icon{left:auto;right:24px}md-menu-content.md-menu-bar-menu.md-dense md-menu-item.md-indent .md-menu>.md-button,md-menu-content.md-menu-bar-menu.md-dense md-menu-item.md-indent>.md-button{padding:0 32px 0 64px}[dir=rtl] md-menu-content.md-menu-bar-menu.md-dense md-menu-item.md-indent .md-menu>.md-button,[dir=rtl] md-menu-content.md-menu-bar-menu.md-dense md-menu-item.md-indent>.md-button{padding:0 64px 0 32px}md-menu-content.md-menu-bar-menu.md-dense .md-button{min-height:0;height:32px}md-menu-content.md-menu-bar-menu.md-dense .md-button span{float:left}[dir=rtl] md-menu-content.md-menu-bar-menu.md-dense .md-button span{float:right}md-menu-content.md-menu-bar-menu.md-dense .md-button span.md-alt-text{float:right;margin:0 8px}[dir=rtl] md-menu-content.md-menu-bar-menu.md-dense .md-button span.md-alt-text{float:left}md-menu-content.md-menu-bar-menu.md-dense md-menu-divider{margin:8px 0}md-menu-content.md-menu-bar-menu.md-dense .md-menu>.md-button,md-menu-content.md-menu-bar-menu.md-dense md-menu-item>.md-button{text-align:left}[dir=rtl] md-menu-content.md-menu-bar-menu.md-dense .md-menu>.md-button,[dir=rtl] md-menu-content.md-menu-bar-menu.md-dense md-menu-item>.md-button{text-align:right}md-menu-content.md-menu-bar-menu.md-dense .md-menu{padding:0}md-menu-content.md-menu-bar-menu.md-dense .md-menu>.md-button{position:relative;margin:0;width:100%;text-transform:none;font-weight:400;border-radius:0;padding-left:16px}[dir=rtl] md-menu-content.md-menu-bar-menu.md-dense .md-menu>.md-button{padding-left:0;padding-right:16px}md-menu-content.md-menu-bar-menu.md-dense .md-menu>.md-button:after{display:block;content:"\25BC";position:absolute;top:0;speak:none;-webkit-transform:rotate(270deg) scaleY(.45) scaleX(.9);transform:rotate(270deg) scaleY(.45) scaleX(.9);right:28px}[dir=rtl] md-menu-content.md-menu-bar-menu.md-dense .md-menu>.md-button:after{-webkit-transform:rotate(90deg) scaleY(.45) scaleX(.9);transform:rotate(90deg) scaleY(.45) scaleX(.9);right:auto;left:28px}.md-open-menu-container{position:fixed;left:0;top:0;z-index:100;opacity:0;border-radius:2px}.md-open-menu-container md-menu-divider{margin-top:4px;margin-bottom:4px;height:1px;min-height:1px;max-height:1px;width:100%}.md-open-menu-container md-menu-content>*{opacity:0}.md-open-menu-container:not(.md-clickable){pointer-events:none}.md-open-menu-container.md-active{opacity:1;-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transition-duration:.2s;transition-duration:.2s}.md-open-menu-container.md-active>md-menu-content>*{opacity:1;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-delay:.1s;transition-delay:.1s}.md-open-menu-container.md-leave{opacity:0;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-duration:.25s;transition-duration:.25s}md-menu-content{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;padding:8px 0;max-height:304px;overflow-y:auto}md-menu-content.md-dense{max-height:208px}md-menu-content.md-dense md-menu-item{height:32px;min-height:0}md-menu-item{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row;min-height:48px;height:48px;-webkit-align-content:center;align-content:center;-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}md-menu-item>*{width:100%;margin:auto 0;padding-left:16px;padding-right:16px}md-menu-item>a.md-button{padding-top:5px}md-menu-item>.md-button{text-align:left;display:inline-block;border-radius:0;margin:auto 0;font-size:15px;text-transform:none;font-weight:400;height:100%;padding-left:16px;padding-right:16px;width:100%}md-menu-item>.md-button::-moz-focus-inner{padding:0;border:0}[dir=rtl] md-menu-item>.md-button{text-align:right}md-menu-item>.md-button md-icon{margin:auto 16px auto 0}[dir=rtl] md-menu-item>.md-button md-icon{margin:auto 0 auto 16px}md-menu-item>.md-button p{display:inline-block;margin:auto}md-menu-item>.md-button span{margin-top:auto;margin-bottom:auto}md-menu-item>.md-button .md-ripple-container{border-radius:inherit}md-toolbar .md-menu{height:auto;margin:auto;padding:0}@media (max-width:959px){md-menu-content{min-width:112px}md-menu-content[width="3"]{min-width:168px}md-menu-content[width="4"]{min-width:224px}md-menu-content[width="5"]{min-width:280px}md-menu-content[width="6"]{min-width:336px}md-menu-content[width="7"]{min-width:392px}}@media (min-width:960px){md-menu-content{min-width:96px}md-menu-content[width="3"]{min-width:192px}md-menu-content[width="4"]{min-width:256px}md-menu-content[width="5"]{min-width:320px}md-menu-content[width="6"]{min-width:384px}md-menu-content[width="7"]{min-width:448px}}.md-nav-bar{border-style:solid;border-width:0 0 1px;height:48px;position:relative}._md-nav-bar-list{outline:none;list-style:none;margin:0;padding:0;box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}.md-nav-item:first-of-type{margin-left:8px}.md-button._md-nav-button{line-height:24px;margin:0 4px;padding:12px 16px;-webkit-transition:background-color .35s cubic-bezier(.35,0,.25,1);transition:background-color .35s cubic-bezier(.35,0,.25,1)}.md-button._md-nav-button:focus{outline:none}.md-button._md-nav-button:hover{background-color:inherit}md-nav-ink-bar{bottom:0;height:2px;left:auto;position:absolute;right:auto;background-color:#000}md-nav-ink-bar._md-left{-webkit-transition:left .125s cubic-bezier(.35,0,.25,1),right .25s cubic-bezier(.35,0,.25,1);transition:left .125s cubic-bezier(.35,0,.25,1),right .25s cubic-bezier(.35,0,.25,1)}md-nav-ink-bar._md-right{-webkit-transition:left .25s cubic-bezier(.35,0,.25,1),right .125s cubic-bezier(.35,0,.25,1);transition:left .25s cubic-bezier(.35,0,.25,1),right .125s cubic-bezier(.35,0,.25,1)}md-nav-ink-bar.ng-animate{-webkit-transition:none;transition:none}md-nav-extra-content{min-height:48px;padding-right:12px}@-webkit-keyframes indeterminate-rotate{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes indeterminate-rotate{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}md-progress-circular{position:relative;display:block}md-progress-circular._md-progress-circular-disabled{visibility:hidden}md-progress-circular.md-mode-indeterminate svg{-webkit-animation:indeterminate-rotate 1568.63ms linear infinite;animation:indeterminate-rotate 1568.63ms linear infinite}md-progress-circular svg{position:absolute;overflow:visible;top:0;left:0}md-progress-linear{display:block;position:relative;width:100%;height:5px;padding-top:0!important;margin-bottom:0!important}md-progress-linear._md-progress-linear-disabled{visibility:hidden}md-progress-linear .md-container{display:block;position:relative;overflow:hidden;width:100%;height:5px;-webkit-transform:translate(0,0) scale(1,1);transform:translate(0,0) scale(1,1)}md-progress-linear .md-container .md-bar{position:absolute;left:0;top:0;bottom:0;width:100%;height:5px}md-progress-linear .md-container .md-dashed:before{content:"";display:none;position:absolute;margin-top:0;height:5px;width:100%;background-color:transparent;background-size:10px 10px!important;background-position:0 -23px}md-progress-linear .md-container .md-bar1,md-progress-linear .md-container .md-bar2{-webkit-transition:-webkit-transform .2s linear;transition:-webkit-transform .2s linear;transition:transform .2s linear;transition:transform .2s linear,-webkit-transform .2s linear}md-progress-linear .md-container.md-mode-query .md-bar1{display:none}md-progress-linear .md-container.md-mode-query .md-bar2{-webkit-transition:all .2s linear;transition:all .2s linear;-webkit-animation:query .8s infinite cubic-bezier(.39,.575,.565,1);animation:query .8s infinite cubic-bezier(.39,.575,.565,1)}md-progress-linear .md-container.md-mode-determinate .md-bar1{display:none}md-progress-linear .md-container.md-mode-indeterminate .md-bar1{-webkit-animation:md-progress-linear-indeterminate-scale-1 4s infinite,md-progress-linear-indeterminate-1 4s infinite;animation:md-progress-linear-indeterminate-scale-1 4s infinite,md-progress-linear-indeterminate-1 4s infinite}md-progress-linear .md-container.md-mode-indeterminate .md-bar2{-webkit-animation:md-progress-linear-indeterminate-scale-2 4s infinite,md-progress-linear-indeterminate-2 4s infinite;animation:md-progress-linear-indeterminate-scale-2 4s infinite,md-progress-linear-indeterminate-2 4s infinite}md-progress-linear .md-container.ng-hide ._md-progress-linear-disabled md-progress-linear .md-container{-webkit-animation:none;animation:none}md-progress-linear .md-container.ng-hide ._md-progress-linear-disabled md-progress-linear .md-container .md-bar1,md-progress-linear .md-container.ng-hide ._md-progress-linear-disabled md-progress-linear .md-container .md-bar2{-webkit-animation-name:none;animation-name:none}md-progress-linear .md-container.md-mode-buffer{background-color:transparent!important;-webkit-transition:all .2s linear;transition:all .2s linear}md-progress-linear .md-container.md-mode-buffer .md-dashed:before{display:block;-webkit-animation:buffer 3s infinite linear;animation:buffer 3s infinite linear}@-webkit-keyframes query{0%{opacity:1;-webkit-transform:translateX(35%) scale(.3,1);transform:translateX(35%) scale(.3,1)}to{opacity:0;-webkit-transform:translateX(-50%) scale(0,1);transform:translateX(-50%) scale(0,1)}}@keyframes query{0%{opacity:1;-webkit-transform:translateX(35%) scale(.3,1);transform:translateX(35%) scale(.3,1)}to{opacity:0;-webkit-transform:translateX(-50%) scale(0,1);transform:translateX(-50%) scale(0,1)}}@-webkit-keyframes buffer{0%{opacity:1;background-position:0 -23px}50%{opacity:0}to{opacity:1;background-position:-200px -23px}}@keyframes buffer{0%{opacity:1;background-position:0 -23px}50%{opacity:0}to{opacity:1;background-position:-200px -23px}}@-webkit-keyframes md-progress-linear-indeterminate-scale-1{0%{-webkit-transform:scaleX(.1);transform:scaleX(.1);-webkit-animation-timing-function:linear;animation-timing-function:linear}36.6%{-webkit-transform:scaleX(.1);transform:scaleX(.1);-webkit-animation-timing-function:cubic-bezier(.33473,.12482,.78584,1);animation-timing-function:cubic-bezier(.33473,.12482,.78584,1)}69.15%{-webkit-transform:scaleX(.83);transform:scaleX(.83);-webkit-animation-timing-function:cubic-bezier(.22573,0,.23365,1.37098);animation-timing-function:cubic-bezier(.22573,0,.23365,1.37098)}to{-webkit-transform:scaleX(.1);transform:scaleX(.1)}}@keyframes md-progress-linear-indeterminate-scale-1{0%{-webkit-transform:scaleX(.1);transform:scaleX(.1);-webkit-animation-timing-function:linear;animation-timing-function:linear}36.6%{-webkit-transform:scaleX(.1);transform:scaleX(.1);-webkit-animation-timing-function:cubic-bezier(.33473,.12482,.78584,1);animation-timing-function:cubic-bezier(.33473,.12482,.78584,1)}69.15%{-webkit-transform:scaleX(.83);transform:scaleX(.83);-webkit-animation-timing-function:cubic-bezier(.22573,0,.23365,1.37098);animation-timing-function:cubic-bezier(.22573,0,.23365,1.37098)}to{-webkit-transform:scaleX(.1);transform:scaleX(.1)}}@-webkit-keyframes md-progress-linear-indeterminate-1{0%{left:-105.16667%;-webkit-animation-timing-function:linear;animation-timing-function:linear}20%{left:-105.16667%;-webkit-animation-timing-function:cubic-bezier(.5,0,.70173,.49582);animation-timing-function:cubic-bezier(.5,0,.70173,.49582)}69.15%{left:21.5%;-webkit-animation-timing-function:cubic-bezier(.30244,.38135,.55,.95635);animation-timing-function:cubic-bezier(.30244,.38135,.55,.95635)}to{left:95.44444%}}@keyframes md-progress-linear-indeterminate-1{0%{left:-105.16667%;-webkit-animation-timing-function:linear;animation-timing-function:linear}20%{left:-105.16667%;-webkit-animation-timing-function:cubic-bezier(.5,0,.70173,.49582);animation-timing-function:cubic-bezier(.5,0,.70173,.49582)}69.15%{left:21.5%;-webkit-animation-timing-function:cubic-bezier(.30244,.38135,.55,.95635);animation-timing-function:cubic-bezier(.30244,.38135,.55,.95635)}to{left:95.44444%}}@-webkit-keyframes md-progress-linear-indeterminate-scale-2{0%{-webkit-transform:scaleX(.1);transform:scaleX(.1);-webkit-animation-timing-function:cubic-bezier(.20503,.05705,.57661,.45397);animation-timing-function:cubic-bezier(.20503,.05705,.57661,.45397)}19.15%{-webkit-transform:scaleX(.57);transform:scaleX(.57);-webkit-animation-timing-function:cubic-bezier(.15231,.19643,.64837,1.00432);animation-timing-function:cubic-bezier(.15231,.19643,.64837,1.00432)}44.15%{-webkit-transform:scaleX(.91);transform:scaleX(.91);-webkit-animation-timing-function:cubic-bezier(.25776,-.00316,.21176,1.38179);animation-timing-function:cubic-bezier(.25776,-.00316,.21176,1.38179)}to{-webkit-transform:scaleX(.1);transform:scaleX(.1)}}@keyframes md-progress-linear-indeterminate-scale-2{0%{-webkit-transform:scaleX(.1);transform:scaleX(.1);-webkit-animation-timing-function:cubic-bezier(.20503,.05705,.57661,.45397);animation-timing-function:cubic-bezier(.20503,.05705,.57661,.45397)}19.15%{-webkit-transform:scaleX(.57);transform:scaleX(.57);-webkit-animation-timing-function:cubic-bezier(.15231,.19643,.64837,1.00432);animation-timing-function:cubic-bezier(.15231,.19643,.64837,1.00432)}44.15%{-webkit-transform:scaleX(.91);transform:scaleX(.91);-webkit-animation-timing-function:cubic-bezier(.25776,-.00316,.21176,1.38179);animation-timing-function:cubic-bezier(.25776,-.00316,.21176,1.38179)}to{-webkit-transform:scaleX(.1);transform:scaleX(.1)}}@-webkit-keyframes md-progress-linear-indeterminate-2{0%{left:-54.88889%;-webkit-animation-timing-function:cubic-bezier(.15,0,.51506,.40968);animation-timing-function:cubic-bezier(.15,0,.51506,.40968)}25%{left:-17.25%;-webkit-animation-timing-function:cubic-bezier(.31033,.28406,.8,.73372);animation-timing-function:cubic-bezier(.31033,.28406,.8,.73372)}48.35%{left:29.5%;-webkit-animation-timing-function:cubic-bezier(.4,.62703,.6,.90203);animation-timing-function:cubic-bezier(.4,.62703,.6,.90203)}to{left:117.38889%}}@keyframes md-progress-linear-indeterminate-2{0%{left:-54.88889%;-webkit-animation-timing-function:cubic-bezier(.15,0,.51506,.40968);animation-timing-function:cubic-bezier(.15,0,.51506,.40968)}25%{left:-17.25%;-webkit-animation-timing-function:cubic-bezier(.31033,.28406,.8,.73372);animation-timing-function:cubic-bezier(.31033,.28406,.8,.73372)}48.35%{left:29.5%;-webkit-animation-timing-function:cubic-bezier(.4,.62703,.6,.90203);animation-timing-function:cubic-bezier(.4,.62703,.6,.90203)}to{left:117.38889%}}md-input-container:not([md-no-float]) .md-select-placeholder span:first-child{-webkit-transition:-webkit-transform .4s cubic-bezier(.25,.8,.25,1);transition:-webkit-transform .4s cubic-bezier(.25,.8,.25,1);transition:transform .4s cubic-bezier(.25,.8,.25,1);transition:transform .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);-webkit-transform-origin:left top;transform-origin:left top}[dir=rtl] md-input-container:not([md-no-float]) .md-select-placeholder span:first-child{-webkit-transform-origin:right top;transform-origin:right top}md-input-container.md-input-focused:not([md-no-float]) .md-select-placeholder span:first-child{-webkit-transform:translateY(-22px) translateX(-2px) scale(.75);transform:translateY(-22px) translateX(-2px) scale(.75)}.md-select-menu-container{position:fixed;left:0;top:0;z-index:90;opacity:0;display:none;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.md-select-menu-container:not(.md-clickable){pointer-events:none}.md-select-menu-container md-progress-circular{display:table;margin:24px auto!important}.md-select-menu-container.md-active{display:block;opacity:1}.md-select-menu-container.md-active md-select-menu{-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transition-duration:.15s;transition-duration:.15s}.md-select-menu-container.md-active md-select-menu>*{opacity:1;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-duration:.15s;transition-duration:.15s;-webkit-transition-delay:.1s;transition-delay:.1s}.md-select-menu-container.md-leave{opacity:0;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-duration:.25s;transition-duration:.25s}md-input-container>md-select{margin:0;-webkit-box-ordinal-group:3;-webkit-order:2;order:2}md-input-container:not(.md-input-has-value) md-select.ng-required:not(.md-no-asterisk) .md-select-value span:first-child:after,md-input-container:not(.md-input-has-value) md-select[required]:not(.md-no-asterisk) .md-select-value span:first-child:after{content:" *";font-size:13px;vertical-align:top}md-input-container.md-input-invalid md-select .md-select-value{border-bottom-style:solid;padding-bottom:1px}md-select{display:-webkit-box;display:-webkit-flex;display:flex;margin:20px 0 26px}md-select.ng-required.ng-invalid:not(.md-no-asterisk) .md-select-value span:first-child:after,md-select[required].ng-invalid:not(.md-no-asterisk) .md-select-value span:first-child:after{content:" *";font-size:13px;vertical-align:top}md-select[disabled] .md-select-value{background-position:0 bottom;background-size:4px 1px;background-repeat:repeat-x;margin-bottom:-1px}md-select:focus{outline:none}md-select[disabled]:hover{cursor:default}md-select:not([disabled]):hover{cursor:pointer}md-select:not([disabled]).ng-invalid.ng-touched .md-select-value{border-bottom-style:solid;padding-bottom:1px}md-select:not([disabled]):focus .md-select-value{border-bottom-width:2px;border-bottom-style:solid;padding-bottom:0}md-select:not([disabled]):focus.ng-invalid.ng-touched .md-select-value{padding-bottom:0}md-input-container.md-input-has-value .md-select-value>span:not(.md-select-icon){-webkit-transform:translate3d(0,1px,0);transform:translate3d(0,1px,0)}.md-select-value{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;padding:2px 2px 1px;border-bottom-width:1px;border-bottom-style:solid;background-color:transparent;position:relative;box-sizing:content-box;min-width:64px;min-height:26px;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.md-select-value>span:not(.md-select-icon){max-width:100%;-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.md-select-value>span:not(.md-select-icon) .md-text{display:inline}.md-select-value .md-select-icon{display:block;-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;text-align:end;width:24px;margin:0 4px;-webkit-transform:translate3d(0,-2px,0);transform:translate3d(0,-2px,0);font-size:1.2rem}.md-select-value .md-select-icon:after{display:block;content:"\25BC";position:relative;top:2px;speak:none;font-size:13px;-webkit-transform:scaleY(.5) scaleX(1);transform:scaleY(.5) scaleX(1)}.md-select-value.md-select-placeholder{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-ordinal-group:2;-webkit-order:1;order:1;pointer-events:none;-webkit-font-smoothing:antialiased;padding-left:2px;z-index:1}md-select-menu{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;box-shadow:0 1px 3px 0 rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12);max-height:256px;min-height:48px;overflow-y:hidden;-webkit-transform-origin:left top;transform-origin:left top;-webkit-transform:scale(1);transform:scale(1)}md-select-menu.md-reverse{-webkit-box-orient:vertical;-webkit-box-direction:reverse;-webkit-flex-direction:column-reverse;flex-direction:column-reverse}md-select-menu:not(.md-overflow) md-content{padding-top:8px;padding-bottom:8px}[dir=rtl] md-select-menu{-webkit-transform-origin:right top;transform-origin:right top}md-select-menu md-content{min-width:136px;min-height:48px;max-height:256px;overflow-y:auto}md-select-menu>*{opacity:0}md-option{cursor:pointer;position:relative;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;width:auto;-webkit-transition:background .15s linear;transition:background .15s linear;padding:0 16px;height:48px}md-option[disabled]{cursor:default}md-option:focus{outline:none}md-option .md-text{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}md-optgroup{display:block}md-optgroup label{display:block;font-size:14px;text-transform:uppercase;padding:16px;font-weight:500}md-optgroup md-option{padding-left:32px;padding-right:32px}@media screen and (-ms-high-contrast:active){.md-select-backdrop{background-color:transparent}md-select-menu{border:1px solid #fff}}md-select-menu[multiple] md-option.md-checkbox-enabled{padding-left:40px;padding-right:16px}[dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled{padding-left:16px;padding-right:40px}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);box-sizing:border-box;display:inline-block;width:20px;height:20px;left:0;right:auto}[dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled .md-container{left:auto;right:0}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container:before{box-sizing:border-box;background-color:transparent;border-radius:50%;content:"";position:absolute;display:block;height:auto;left:0;top:0;right:0;bottom:0;-webkit-transition:all .5s;transition:all .5s;width:auto}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container:after{box-sizing:border-box;content:"";position:absolute;top:-10px;right:-10px;bottom:-10px;left:-10px}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container .md-ripple-container{position:absolute;display:block;width:auto;height:auto;left:-15px;top:-15px;right:-15px;bottom:-15px}md-select-menu[multiple] md-option.md-checkbox-enabled .md-icon{box-sizing:border-box;-webkit-transition:.24s;transition:.24s;position:absolute;top:0;left:0;width:20px;height:20px;border-width:2px;border-style:solid;border-radius:2px}md-select-menu[multiple] md-option.md-checkbox-enabled[selected] .md-icon{border-color:transparent}md-select-menu[multiple] md-option.md-checkbox-enabled[selected] .md-icon:after{box-sizing:border-box;-webkit-transform:rotate(45deg);transform:rotate(45deg);position:absolute;left:4.66667px;top:.22222px;display:table;width:6.66667px;height:13.33333px;border-width:2px;border-style:solid;border-top:0;border-left:0;content:""}md-select-menu[multiple] md-option.md-checkbox-enabled[disabled]{cursor:default}md-select-menu[multiple] md-option.md-checkbox-enabled.md-indeterminate .md-icon:after{box-sizing:border-box;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:table;width:12px;height:2px;border-width:2px;border-style:solid;border-top:0;border-left:0;content:""}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container{margin-left:10.66667px;margin-right:auto}[dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled .md-container{margin-left:auto;margin-right:10.66667px}md-sidenav{box-sizing:border-box;position:absolute;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;z-index:60;width:320px;max-width:320px;bottom:0;overflow:auto;-webkit-overflow-scrolling:touch}md-sidenav ul{list-style:none}md-sidenav.md-closed{display:none}md-sidenav.md-closed-add,md-sidenav.md-closed-remove{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}md-sidenav.md-closed-add.md-closed-add-active,md-sidenav.md-closed-remove.md-closed-remove-active{-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1)}md-sidenav.md-closed.md-locked-open-add,md-sidenav.md-locked-open,md-sidenav.md-locked-open-add,md-sidenav.md-locked-open-remove,md-sidenav.md-locked-open-remove.md-closed,md-sidenav.md-locked-open.md-closed,md-sidenav.md-locked-open.md-closed.md-sidenav-left,md-sidenav.md-locked-open.md-closed.md-sidenav-right{position:static;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}md-sidenav.md-closed.md-locked-open-add:not(.md-locked-open-add-active){width:0!important;min-width:0!important}md-sidenav.md-closed.md-locked-open-add-active,md-sidenav.md-closed.md-locked-open-add:not(.md-locked-open-add-active),md-sidenav.md-locked-open-remove-active{-webkit-transition:width .3s cubic-bezier(.55,0,.55,.2),min-width .3s cubic-bezier(.55,0,.55,.2);transition:width .3s cubic-bezier(.55,0,.55,.2),min-width .3s cubic-bezier(.55,0,.55,.2)}md-sidenav.md-locked-open-remove-active{width:0!important;min-width:0!important}.md-sidenav-backdrop.md-locked-open{display:none}.md-sidenav-left,md-sidenav{left:0;top:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.md-sidenav-left.md-closed,md-sidenav.md-closed{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.md-sidenav-right{left:100%;top:0;-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}.md-sidenav-right.md-closed{-webkit-transform:translate(0,0);transform:translate(0,0)}@media (min-width:600px){md-sidenav{max-width:400px}}@media (max-width:456px){md-sidenav{width:calc(100% - 56px);min-width:calc(100% - 56px);max-width:calc(100% - 56px)}}@media screen and (-ms-high-contrast:active){.md-sidenav-left,md-sidenav{border-right:1px solid #fff}.md-sidenav-right{border-left:1px solid #fff}}md-radio-button{box-sizing:border-box;display:block;margin-bottom:16px;white-space:nowrap;cursor:pointer;position:relative}md-radio-button[disabled],md-radio-button[disabled] .md-container{cursor:default}md-radio-button .md-container{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);box-sizing:border-box;display:inline-block;width:20px;height:20px;cursor:pointer;left:0;right:auto}[dir=rtl] md-radio-button .md-container{left:auto;right:0}md-radio-button .md-container .md-ripple-container{position:absolute;display:block;width:auto;height:auto;left:-15px;top:-15px;right:-15px;bottom:-15px}md-radio-button .md-container:before{box-sizing:border-box;background-color:transparent;border-radius:50%;content:"";position:absolute;display:block;height:auto;left:0;top:0;right:0;bottom:0;-webkit-transition:all .5s;transition:all .5s;width:auto}md-radio-button.md-align-top-left>div.md-container{top:12px}md-radio-button .md-off{border-style:solid;border-width:2px;-webkit-transition:border-color .28s ease;transition:border-color .28s ease}md-radio-button .md-off,md-radio-button .md-on{box-sizing:border-box;position:absolute;top:0;left:0;width:20px;height:20px;border-radius:50%}md-radio-button .md-on{-webkit-transition:-webkit-transform .28s ease;transition:-webkit-transform .28s ease;transition:transform .28s ease;transition:transform .28s ease,-webkit-transform .28s ease;-webkit-transform:scale(0);transform:scale(0)}md-radio-button.md-checked .md-on{-webkit-transform:scale(.5);transform:scale(.5)}md-radio-button .md-label{box-sizing:border-box;position:relative;display:inline-block;margin-left:30px;margin-right:0;vertical-align:middle;white-space:normal;pointer-events:none;width:auto}[dir=rtl] md-radio-button .md-label{margin-left:0;margin-right:30px}md-radio-group.layout-column md-radio-button,md-radio-group.layout-gt-lg-column md-radio-button,md-radio-group.layout-gt-md-column md-radio-button,md-radio-group.layout-gt-sm-column md-radio-button,md-radio-group.layout-gt-xs-column md-radio-button,md-radio-group.layout-lg-column md-radio-button,md-radio-group.layout-md-column md-radio-button,md-radio-group.layout-sm-column md-radio-button,md-radio-group.layout-xl-column md-radio-button,md-radio-group.layout-xs-column md-radio-button{margin-bottom:16px}md-radio-group.layout-gt-lg-row md-radio-button,md-radio-group.layout-gt-md-row md-radio-button,md-radio-group.layout-gt-sm-row md-radio-button,md-radio-group.layout-gt-xs-row md-radio-button,md-radio-group.layout-lg-row md-radio-button,md-radio-group.layout-md-row md-radio-button,md-radio-group.layout-row md-radio-button,md-radio-group.layout-sm-row md-radio-button,md-radio-group.layout-xl-row md-radio-button,md-radio-group.layout-xs-row md-radio-button{margin:0 16px 0 0}[dir=rtl] md-radio-group.layout-gt-lg-row md-radio-button,[dir=rtl] md-radio-group.layout-gt-md-row md-radio-button,[dir=rtl] md-radio-group.layout-gt-sm-row md-radio-button,[dir=rtl] md-radio-group.layout-gt-xs-row md-radio-button,[dir=rtl] md-radio-group.layout-lg-row md-radio-button,[dir=rtl] md-radio-group.layout-md-row md-radio-button,[dir=rtl] md-radio-group.layout-row md-radio-button,[dir=rtl] md-radio-group.layout-sm-row md-radio-button,[dir=rtl] md-radio-group.layout-xl-row md-radio-button,[dir=rtl] md-radio-group.layout-xs-row md-radio-button{margin-left:16px;margin-right:0}md-radio-group.layout-gt-lg-row md-radio-button:last-of-type,md-radio-group.layout-gt-md-row md-radio-button:last-of-type,md-radio-group.layout-gt-sm-row md-radio-button:last-of-type,md-radio-group.layout-gt-xs-row md-radio-button:last-of-type,md-radio-group.layout-lg-row md-radio-button:last-of-type,md-radio-group.layout-md-row md-radio-button:last-of-type,md-radio-group.layout-row md-radio-button:last-of-type,md-radio-group.layout-sm-row md-radio-button:last-of-type,md-radio-group.layout-xl-row md-radio-button:last-of-type,md-radio-group.layout-xs-row md-radio-button:last-of-type{margin-left:0;margin-right:0}md-radio-group:focus{outline:none}md-radio-group.md-focused .md-checked .md-container:before{left:-8px;top:-8px;right:-8px;bottom:-8px}md-radio-group[disabled] md-radio-button,md-radio-group[disabled] md-radio-button .md-container{cursor:default}.md-inline-form md-radio-group{margin:18px 0 19px}.md-inline-form md-radio-group md-radio-button{display:inline-block;height:30px;padding:2px;box-sizing:border-box;margin-top:0;margin-bottom:0}@media screen and (-ms-high-contrast:active){md-radio-button.md-default-theme .md-on{background-color:#fff}}@-webkit-keyframes sliderFocusThumb{0%{-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1);transform:scale(1)}to{-webkit-transform:scale(.7);transform:scale(.7)}}@keyframes sliderFocusThumb{0%{-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1);transform:scale(1)}to{-webkit-transform:scale(.7);transform:scale(.7)}}@-webkit-keyframes sliderDiscreteFocusThumb{0%{-webkit-transform:scale(.7);transform:scale(.7)}50%{-webkit-transform:scale(.8);transform:scale(.8)}to{-webkit-transform:scale(0);transform:scale(0)}}@keyframes sliderDiscreteFocusThumb{0%{-webkit-transform:scale(.7);transform:scale(.7)}50%{-webkit-transform:scale(.8);transform:scale(.8)}to{-webkit-transform:scale(0);transform:scale(0)}}@-webkit-keyframes sliderDiscreteFocusRing{0%{-webkit-transform:scale(.7);transform:scale(.7);opacity:0}50%{-webkit-transform:scale(1);transform:scale(1);opacity:1}to{-webkit-transform:scale(0);transform:scale(0)}}@keyframes sliderDiscreteFocusRing{0%{-webkit-transform:scale(.7);transform:scale(.7);opacity:0}50%{-webkit-transform:scale(1);transform:scale(1);opacity:1}to{-webkit-transform:scale(0);transform:scale(0)}}md-slider{height:48px;min-width:128px;position:relative;margin-left:4px;margin-right:4px;padding:0;display:block;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}md-slider *,md-slider :after{box-sizing:border-box}md-slider .md-slider-wrapper{outline:none;width:100%;height:100%}md-slider .md-slider-content{position:relative}md-slider .md-track-container{width:100%;position:absolute;top:23px;height:2px}md-slider .md-track{position:absolute;left:0;right:0;height:100%}md-slider .md-track-fill{-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transition-property:width,height;transition-property:width,height}md-slider .md-track-ticks{position:absolute;left:0;right:0;height:100%}md-slider .md-track-ticks canvas{width:100%;height:100%}md-slider .md-thumb-container{position:absolute;left:0;top:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0);-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transition-property:left,right,bottom;transition-property:left,right,bottom}[dir=rtl] md-slider .md-thumb-container{left:auto;right:0}md-slider .md-thumb{z-index:1;position:absolute;left:-10px;top:14px;width:20px;height:20px;border-radius:20px;-webkit-transform:scale(.7);transform:scale(.7);-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1)}[dir=rtl] md-slider .md-thumb{left:auto;right:-10px}md-slider .md-thumb:after{content:"";position:absolute;width:20px;height:20px;border-radius:20px;border-width:3px;border-style:solid;-webkit-transition:inherit;transition:inherit}md-slider .md-sign{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center;position:absolute;left:-14px;top:-17px;width:28px;height:28px;border-radius:28px;-webkit-transform:scale(.4) translate3d(0,67.5px,0);transform:scale(.4) translate3d(0,67.5px,0);-webkit-transition:all .3s cubic-bezier(.35,0,.25,1);transition:all .3s cubic-bezier(.35,0,.25,1)}md-slider .md-sign:after{position:absolute;content:"";left:0;border-radius:16px;top:19px;border-left:14px solid transparent;border-right:14px solid transparent;border-top-width:16px;border-top-style:solid;opacity:0;-webkit-transform:translate3d(0,-8px,0);transform:translate3d(0,-8px,0);-webkit-transition:all .2s cubic-bezier(.35,0,.25,1);transition:all .2s cubic-bezier(.35,0,.25,1)}[dir=rtl] md-slider .md-sign:after{left:auto;right:0}md-slider .md-sign .md-thumb-text{z-index:1;font-size:12px;font-weight:700}md-slider .md-focus-ring{position:absolute;left:-17px;top:7px;width:34px;height:34px;border-radius:34px;-webkit-transform:scale(.7);transform:scale(.7);opacity:0;-webkit-transition:all .35s cubic-bezier(.35,0,.25,1);transition:all .35s cubic-bezier(.35,0,.25,1)}[dir=rtl] md-slider .md-focus-ring{left:auto;right:-17px}md-slider .md-disabled-thumb{position:absolute;left:-14px;top:10px;width:28px;height:28px;border-radius:28px;-webkit-transform:scale(.5);transform:scale(.5);border-width:4px;border-style:solid;display:none}[dir=rtl] md-slider .md-disabled-thumb{left:auto;right:-14px}md-slider.md-min .md-sign{opacity:0}md-slider:focus{outline:none}md-slider.md-dragging .md-thumb-container,md-slider.md-dragging .md-track-fill{-webkit-transition:none;transition:none}md-slider:not([md-discrete]) .md-sign,md-slider:not([md-discrete]) .md-track-ticks{display:none}md-slider:not([md-discrete]):not([disabled]) .md-slider-wrapper .md-thumb:hover{-webkit-transform:scale(.8);transform:scale(.8)}md-slider:not([md-discrete]):not([disabled]) .md-slider-wrapper.md-focused .md-focus-ring{-webkit-transform:scale(1);transform:scale(1);opacity:1}md-slider:not([md-discrete]):not([disabled]) .md-slider-wrapper.md-focused .md-thumb{-webkit-animation:sliderFocusThumb .7s cubic-bezier(.35,0,.25,1);animation:sliderFocusThumb .7s cubic-bezier(.35,0,.25,1)}md-slider:not([md-discrete]):not([disabled]).md-active .md-slider-wrapper .md-thumb{-webkit-transform:scale(1);transform:scale(1)}md-slider[md-discrete]:not([disabled]) .md-slider-wrapper.md-focused .md-focus-ring{-webkit-transform:scale(0);transform:scale(0);-webkit-animation:sliderDiscreteFocusRing .5s cubic-bezier(.35,0,.25,1);animation:sliderDiscreteFocusRing .5s cubic-bezier(.35,0,.25,1)}md-slider[md-discrete]:not([disabled]) .md-slider-wrapper.md-focused .md-thumb{-webkit-animation:sliderDiscreteFocusThumb .5s cubic-bezier(.35,0,.25,1);animation:sliderDiscreteFocusThumb .5s cubic-bezier(.35,0,.25,1)}md-slider[md-discrete]:not([disabled]).md-active .md-thumb,md-slider[md-discrete]:not([disabled]) .md-slider-wrapper.md-focused .md-thumb{-webkit-transform:scale(0);transform:scale(0)}md-slider[md-discrete]:not([disabled]).md-active .md-sign,md-slider[md-discrete]:not([disabled]).md-active .md-sign:after,md-slider[md-discrete]:not([disabled]) .md-slider-wrapper.md-focused .md-sign,md-slider[md-discrete]:not([disabled]) .md-slider-wrapper.md-focused .md-sign:after{opacity:1;-webkit-transform:translate3d(0,0,0) scale(1);transform:translate3d(0,0,0) scale(1)}md-slider[md-discrete][disabled][readonly] .md-thumb{-webkit-transform:scale(0);transform:scale(0)}md-slider[md-discrete][disabled][readonly] .md-sign,md-slider[md-discrete][disabled][readonly] .md-sign:after{opacity:1;-webkit-transform:translate3d(0,0,0) scale(1);transform:translate3d(0,0,0) scale(1)}md-slider[disabled] .md-track-fill{display:none}md-slider[disabled] .md-track-ticks,md-slider[disabled]:not([readonly]) .md-sign{opacity:0}md-slider[disabled] .md-thumb{-webkit-transform:scale(.5);transform:scale(.5)}md-slider[disabled] .md-disabled-thumb{display:block}md-slider[md-vertical]{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;min-height:128px;min-width:0}md-slider[md-vertical] .md-slider-wrapper{-webkit-box-flex:1;-webkit-flex:1;flex:1;padding-top:12px;padding-bottom:12px;width:48px;-webkit-align-self:center;align-self:center;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}md-slider[md-vertical] .md-track-container{height:100%;width:2px;top:0;left:calc(50% - 1px)}md-slider[md-vertical] .md-thumb-container{top:auto;margin-bottom:23px;left:calc(50% - 1px);bottom:0}md-slider[md-vertical] .md-thumb-container .md-thumb:after{left:1px}md-slider[md-vertical] .md-thumb-container .md-focus-ring{left:-16px}md-slider[md-vertical] .md-track-fill{bottom:0}md-slider[md-vertical][md-discrete] .md-sign{left:-40px;top:9.5px;-webkit-transform:scale(.4) translate3d(67.5px,0,0);transform:scale(.4) translate3d(67.5px,0,0)}md-slider[md-vertical][md-discrete] .md-sign:after{top:9.5px;left:19px;border-top:14px solid transparent;border-right:0;border-bottom:14px solid transparent;border-left-width:16px;border-left-style:solid;opacity:0;-webkit-transform:translate3d(0,-8px,0);transform:translate3d(0,-8px,0);-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}md-slider[md-vertical][md-discrete] .md-sign .md-thumb-text{z-index:1;font-size:12px;font-weight:700}md-slider[md-vertical][md-discrete].md-active .md-sign:after,md-slider[md-vertical][md-discrete] .md-focused .md-sign:after,md-slider[md-vertical][md-discrete][disabled][readonly] .md-sign:after{top:0}md-slider[md-vertical][disabled][readonly] .md-thumb{-webkit-transform:scale(0);transform:scale(0)}md-slider[md-vertical][disabled][readonly] .md-sign,md-slider[md-vertical][disabled][readonly] .md-sign:after{opacity:1;-webkit-transform:translate3d(0,0,0) scale(1);transform:translate3d(0,0,0) scale(1)}md-slider[md-invert]:not([md-vertical]) .md-track-fill{left:auto;right:0}[dir=rtl] md-slider[md-invert]:not([md-vertical]) .md-track-fill{left:0;right:auto}md-slider[md-invert][md-vertical] .md-track-fill{bottom:auto;top:0}md-slider-container{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}md-slider-container>:first-child:not(md-slider),md-slider-container>:last-child:not(md-slider){min-width:25px;max-width:42px;height:25px;-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transition-property:color,max-width;transition-property:color,max-width}md-slider-container>:first-child:not(md-slider){margin-right:16px}[dir=rtl] md-slider-container>:first-child:not(md-slider){margin-right:auto;margin-left:16px}md-slider-container>:last-child:not(md-slider){margin-left:16px}[dir=rtl] md-slider-container>:last-child:not(md-slider){margin-left:auto;margin-right:16px}md-slider-container[md-vertical]{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}md-slider-container[md-vertical]>:first-child:not(md-slider),md-slider-container[md-vertical]>:last-child:not(md-slider){margin-right:0;margin-left:0;text-align:center}md-slider-container md-input-container input[type=number]{text-align:center;padding-left:15px;height:50px;margin-top:-25px}[dir=rtl] md-slider-container md-input-container input[type=number]{padding-left:0;padding-right:15px}@media screen and (-ms-high-contrast:active){md-slider.md-default-theme .md-track{border-bottom:1px solid #fff}}.md-sticky-clone{z-index:2;top:0;left:0;right:0;position:absolute!important;-webkit-transform:translate3d(-9999px,-9999px,0);transform:translate3d(-9999px,-9999px,0)}.md-sticky-clone[sticky-state=active]{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.md-sticky-clone[sticky-state=active]:not(.md-sticky-no-effect) .md-subheader-inner{-webkit-animation:subheaderStickyHoverIn .3s ease-out both;animation:subheaderStickyHoverIn .3s ease-out both}.md-inline-form md-switch{margin-top:18px;margin-bottom:19px}md-switch{margin:16px 0;white-space:nowrap;cursor:pointer;outline:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;height:30px;line-height:28px;-webkit-box-align:center;-webkit-align-items:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:flex;margin-left:inherit;margin-right:16px}[dir=rtl] md-switch{margin-left:16px;margin-right:inherit}md-switch:last-of-type{margin-left:inherit;margin-right:0}[dir=rtl] md-switch:last-of-type{margin-left:0;margin-right:inherit}md-switch[disabled],md-switch[disabled] .md-container{cursor:default}md-switch .md-container{cursor:-webkit-grab;cursor:grab;width:36px;height:24px;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin-right:8px;float:left}[dir=rtl] md-switch .md-container,md-switch.md-inverted .md-container{margin-right:0;margin-left:8px}[dir=rtl] md-switch.md-inverted .md-container{margin-right:8px;margin-left:0}md-switch:not([disabled]) .md-dragging,md-switch:not([disabled]).md-dragging .md-container{cursor:-webkit-grabbing;cursor:grabbing}md-switch.md-focused:not([disabled]) .md-thumb:before{left:-8px;top:-8px;right:-8px;bottom:-8px}md-switch.md-focused:not([disabled]):not(.md-checked) .md-thumb:before{background-color:rgba(0,0,0,.12)}md-switch .md-label{border-color:transparent;border-width:0;float:left}md-switch .md-bar{left:1px;width:34px;top:5px;height:14px;border-radius:8px;position:absolute}md-switch .md-thumb-container{top:2px;left:0;width:16px;position:absolute;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);z-index:1}md-switch.md-checked .md-thumb-container{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}md-switch .md-thumb{margin:0;outline:none;height:20px;width:20px;box-shadow:0 1px 3px 0 rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12)}md-switch .md-thumb,md-switch .md-thumb:before{position:absolute;left:0;top:0;border-radius:50%}md-switch .md-thumb:before{background-color:transparent;content:"";display:block;height:auto;right:0;bottom:0;-webkit-transition:all .5s;transition:all .5s;width:auto}md-switch .md-thumb .md-ripple-container{position:absolute;display:block;width:auto;height:auto;left:-20px;top:-20px;right:-20px;bottom:-20px}md-switch:not(.md-dragging) .md-bar,md-switch:not(.md-dragging) .md-thumb,md-switch:not(.md-dragging) .md-thumb-container{-webkit-transition:all .08s linear;transition:all .08s linear;-webkit-transition-property:background-color,-webkit-transform;transition-property:background-color,-webkit-transform;transition-property:transform,background-color;transition-property:transform,background-color,-webkit-transform}md-switch:not(.md-dragging) .md-bar,md-switch:not(.md-dragging) .md-thumb{-webkit-transition-delay:.05s;transition-delay:.05s}@media screen and (-ms-high-contrast:active){md-switch.md-default-theme .md-bar{background-color:#666}md-switch.md-default-theme.md-checked .md-bar{background-color:#9e9e9e}md-switch.md-default-theme .md-thumb{background-color:#fff}}@-webkit-keyframes subheaderStickyHoverIn{0%{box-shadow:0 0 0 0 transparent}to{box-shadow:0 2px 4px 0 rgba(0,0,0,.16)}}@keyframes subheaderStickyHoverIn{0%{box-shadow:0 0 0 0 transparent}to{box-shadow:0 2px 4px 0 rgba(0,0,0,.16)}}@-webkit-keyframes subheaderStickyHoverOut{0%{box-shadow:0 2px 4px 0 rgba(0,0,0,.16)}to{box-shadow:0 0 0 0 transparent}}@keyframes subheaderStickyHoverOut{0%{box-shadow:0 2px 4px 0 rgba(0,0,0,.16)}to{box-shadow:0 0 0 0 transparent}}.md-subheader-wrapper:not(.md-sticky-no-effect){-webkit-transition:margin .2s ease-out;transition:margin .2s ease-out}.md-subheader-wrapper:not(.md-sticky-no-effect) .md-subheader{margin:0}.md-subheader-wrapper:not(.md-sticky-no-effect).md-sticky-clone{z-index:2}.md-subheader-wrapper:not(.md-sticky-no-effect)[sticky-state=active]{margin-top:-2px}.md-subheader-wrapper:not(.md-sticky-no-effect):not(.md-sticky-clone)[sticky-prev-state=active] .md-subheader-inner:after{-webkit-animation:subheaderStickyHoverOut .3s ease-out both;animation:subheaderStickyHoverOut .3s ease-out both}.md-subheader{display:block;font-size:14px;font-weight:500;line-height:1em;margin:0;position:relative}.md-subheader .md-subheader-inner{display:block;padding:16px}.md-subheader .md-subheader-content{display:block;z-index:1;position:relative}@-webkit-keyframes md-tab-content-hide{0%{opacity:1}50%{opacity:1}to{opacity:0}}@keyframes md-tab-content-hide{0%{opacity:1}50%{opacity:1}to{opacity:0}}md-tab-data{position:absolute;top:0;left:0;right:0;bottom:0;z-index:-1;opacity:0}md-tabs{display:block;margin:0;border-radius:2px;overflow:hidden;position:relative;-webkit-flex-shrink:0;flex-shrink:0}md-tabs:not(.md-no-tab-content):not(.md-dynamic-height){min-height:248px}md-tabs[md-align-tabs=bottom]{padding-bottom:48px}md-tabs[md-align-tabs=bottom] md-tabs-wrapper{position:absolute;bottom:0;left:0;right:0;height:48px;z-index:2}md-tabs[md-align-tabs=bottom] md-tabs-content-wrapper{top:0;bottom:48px}md-tabs.md-dynamic-height md-tabs-content-wrapper{min-height:0;position:relative;top:auto;left:auto;right:auto;bottom:auto;overflow:visible}md-tabs.md-dynamic-height md-tab-content.md-active{position:relative}md-tabs[md-border-bottom] md-tabs-wrapper{border-width:0 0 1px;border-style:solid}md-tabs[md-border-bottom]:not(.md-dynamic-height) md-tabs-content-wrapper{top:49px}md-tabs-wrapper{display:block;position:relative;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}md-tabs-wrapper md-next-button,md-tabs-wrapper md-prev-button{height:100%;width:32px;position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);line-height:1em;z-index:2;cursor:pointer;font-size:16px;background:transparent no-repeat 50%;-webkit-transition:all .5s cubic-bezier(.35,0,.25,1);transition:all .5s cubic-bezier(.35,0,.25,1)}md-tabs-wrapper md-next-button:focus,md-tabs-wrapper md-prev-button:focus{outline:none}md-tabs-wrapper md-next-button.md-disabled,md-tabs-wrapper md-prev-button.md-disabled{opacity:.25;cursor:default}md-tabs-wrapper md-next-button.ng-leave,md-tabs-wrapper md-prev-button.ng-leave{-webkit-transition:none;transition:none}md-tabs-wrapper md-next-button md-icon,md-tabs-wrapper md-prev-button md-icon{position:absolute;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}md-tabs-wrapper md-prev-button{left:0;background-image:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE3LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPiA8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPiA8c3ZnIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMjQgMjQiIHhtbDpzcGFjZT0icHJlc2VydmUiPiA8ZyBpZD0iSGVhZGVyIj4gPGc+IDxyZWN0IHg9Ii02MTgiIHk9Ii0xMjA4IiBmaWxsPSJub25lIiB3aWR0aD0iMTQwMCIgaGVpZ2h0PSIzNjAwIi8+IDwvZz4gPC9nPiA8ZyBpZD0iTGFiZWwiPiA8L2c+IDxnIGlkPSJJY29uIj4gPGc+IDxwb2x5Z29uIHBvaW50cz0iMTUuNCw3LjQgMTQsNiA4LDEyIDE0LDE4IDE1LjQsMTYuNiAxMC44LDEyIAkJIiBzdHlsZT0iZmlsbDp3aGl0ZTsiLz4gPHJlY3QgZmlsbD0ibm9uZSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ii8+IDwvZz4gPC9nPiA8ZyBpZD0iR3JpZCIgZGlzcGxheT0ibm9uZSI+IDxnIGRpc3BsYXk9ImlubGluZSI+IDwvZz4gPC9nPiA8L3N2Zz4NCg==")}[dir=rtl] md-tabs-wrapper md-prev-button{left:auto;right:0}md-tabs-wrapper md-next-button{right:0;background-image:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE3LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPiA8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPiA8c3ZnIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMjQgMjQiIHhtbDpzcGFjZT0icHJlc2VydmUiPiA8ZyBpZD0iSGVhZGVyIj4gPGc+IDxyZWN0IHg9Ii02MTgiIHk9Ii0xMzM2IiBmaWxsPSJub25lIiB3aWR0aD0iMTQwMCIgaGVpZ2h0PSIzNjAwIi8+IDwvZz4gPC9nPiA8ZyBpZD0iTGFiZWwiPiA8L2c+IDxnIGlkPSJJY29uIj4gPGc+IDxwb2x5Z29uIHBvaW50cz0iMTAsNiA4LjYsNy40IDEzLjIsMTIgOC42LDE2LjYgMTAsMTggMTYsMTIgCQkiIHN0eWxlPSJmaWxsOndoaXRlOyIvPiA8cmVjdCBmaWxsPSJub25lIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz4gPC9nPiA8L2c+IDxnIGlkPSJHcmlkIiBkaXNwbGF5PSJub25lIj4gPGcgZGlzcGxheT0iaW5saW5lIj4gPC9nPiA8L2c+IDwvc3ZnPg0K")}[dir=rtl] md-tabs-wrapper md-next-button{right:auto;left:0}md-tabs-wrapper md-next-button md-icon{-webkit-transform:translate3d(-50%,-50%,0) rotate(180deg);transform:translate3d(-50%,-50%,0) rotate(180deg)}md-tabs-wrapper.md-stretch-tabs md-pagination-wrapper{width:100%;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}md-tabs-wrapper.md-stretch-tabs md-pagination-wrapper md-tab-item{-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}md-tabs-canvas{position:relative;overflow:hidden;display:block;height:48px}md-tabs-canvas:after{content:"";display:table;clear:both}md-tabs-canvas .md-dummy-wrapper{position:absolute;top:0;left:0}[dir=rtl] md-tabs-canvas .md-dummy-wrapper{left:auto;right:0}md-tabs-canvas.md-paginated{margin:0 32px}md-tabs-canvas.md-center-tabs{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;text-align:center}md-tabs-canvas.md-center-tabs .md-tab{float:none;display:inline-block}md-pagination-wrapper{height:48px;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-transition:-webkit-transform .5s cubic-bezier(.35,0,.25,1);transition:-webkit-transform .5s cubic-bezier(.35,0,.25,1);transition:transform .5s cubic-bezier(.35,0,.25,1);transition:transform .5s cubic-bezier(.35,0,.25,1),-webkit-transform .5s cubic-bezier(.35,0,.25,1);position:absolute;left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}md-pagination-wrapper:after{content:"";display:table;clear:both}[dir=rtl] md-pagination-wrapper{left:auto;right:0}md-pagination-wrapper.md-center-tabs{position:relative;-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}md-tabs-content-wrapper{display:block;top:48px;overflow:hidden}md-tab-content,md-tabs-content-wrapper{position:absolute;left:0;right:0;bottom:0}md-tab-content{display:-webkit-box;display:-webkit-flex;display:flex;top:0;-webkit-transition:-webkit-transform .5s cubic-bezier(.35,0,.25,1);transition:-webkit-transform .5s cubic-bezier(.35,0,.25,1);transition:transform .5s cubic-bezier(.35,0,.25,1);transition:transform .5s cubic-bezier(.35,0,.25,1),-webkit-transform .5s cubic-bezier(.35,0,.25,1);overflow:auto;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}md-tab-content.md-no-scroll{bottom:auto;overflow:hidden}md-tab-content.md-no-transition,md-tab-content.ng-leave{-webkit-transition:none;transition:none}md-tab-content.md-left:not(.md-active){-webkit-transform:translateX(-100%);transform:translateX(-100%);-webkit-animation:1s md-tab-content-hide;animation:1s md-tab-content-hide;opacity:0}[dir=rtl] md-tab-content.md-left:not(.md-active){-webkit-transform:translateX(100%);transform:translateX(100%)}md-tab-content.md-left:not(.md-active) *{-webkit-transition:visibility 0s linear;transition:visibility 0s linear;-webkit-transition-delay:.5s;transition-delay:.5s;visibility:hidden}md-tab-content.md-right:not(.md-active){-webkit-transform:translateX(100%);transform:translateX(100%);-webkit-animation:1s md-tab-content-hide;animation:1s md-tab-content-hide;opacity:0}[dir=rtl] md-tab-content.md-right:not(.md-active){-webkit-transform:translateX(-100%);transform:translateX(-100%)}md-tab-content.md-right:not(.md-active) *{-webkit-transition:visibility 0s linear;transition:visibility 0s linear;-webkit-transition-delay:.5s;transition-delay:.5s;visibility:hidden}md-tab-content>div{-webkit-box-flex:1;-webkit-flex:1 0 100%;flex:1 0 100%;min-width:0}md-tab-content>div.ng-leave{-webkit-animation:1s md-tab-content-hide;animation:1s md-tab-content-hide}md-ink-bar{position:absolute;left:auto;right:auto;bottom:0;height:2px}md-ink-bar.md-left{-webkit-transition:left .125s cubic-bezier(.35,0,.25,1),right .25s cubic-bezier(.35,0,.25,1);transition:left .125s cubic-bezier(.35,0,.25,1),right .25s cubic-bezier(.35,0,.25,1)}md-ink-bar.md-right{-webkit-transition:left .25s cubic-bezier(.35,0,.25,1),right .125s cubic-bezier(.35,0,.25,1);transition:left .25s cubic-bezier(.35,0,.25,1),right .125s cubic-bezier(.35,0,.25,1)}md-tab{position:absolute;z-index:-1;left:-9999px}.md-tab{font-size:14px;text-align:center;line-height:24px;padding:12px 24px;-webkit-transition:background-color .35s cubic-bezier(.35,0,.25,1);transition:background-color .35s cubic-bezier(.35,0,.25,1);cursor:pointer;white-space:nowrap;position:relative;text-transform:uppercase;float:left;font-weight:500;box-sizing:border-box;overflow:hidden;text-overflow:ellipsis}[dir=rtl] .md-tab{float:right}.md-tab.md-focused{box-shadow:none;outline:none}.md-tab.md-active{cursor:default}.md-tab.md-disabled{pointer-events:none;touch-action:pan-y;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-user-drag:none;opacity:.5;cursor:default}.md-tab.ng-leave{-webkit-transition:none;transition:none}md-toolbar+md-tabs{border-top-left-radius:0;border-top-right-radius:0}.md-tooltip{pointer-events:none;border-radius:4px;overflow:hidden;opacity:0;font-weight:500;font-size:14px;white-space:nowrap;text-overflow:ellipsis;height:32px;line-height:32px;padding-right:16px;padding-left:16px}.md-tooltip.md-origin-top{-webkit-transform-origin:center bottom;transform-origin:center bottom;margin-top:-24px}.md-tooltip.md-origin-right{-webkit-transform-origin:left center;transform-origin:left center;margin-left:24px}.md-tooltip.md-origin-bottom{-webkit-transform-origin:center top;transform-origin:center top;margin-top:24px}.md-tooltip.md-origin-left{-webkit-transform-origin:right center;transform-origin:right center;margin-left:-24px}@media (min-width:960px){.md-tooltip{font-size:10px;height:22px;line-height:22px;padding-right:8px;padding-left:8px}.md-tooltip.md-origin-top{margin-top:-14px}.md-tooltip.md-origin-right{margin-left:14px}.md-tooltip.md-origin-bottom{margin-top:14px}.md-tooltip.md-origin-left{margin-left:-14px}}.md-tooltip.md-show-add{-webkit-transform:scale(0);transform:scale(0)}.md-tooltip.md-show{-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transform:scale(1);transform:scale(1);opacity:.9}.md-tooltip.md-hide{-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-duration:.1s;transition-duration:.1s;-webkit-transform:scale(0);transform:scale(0);opacity:0}md-toolbar{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;position:relative;z-index:2;font-size:20px;min-height:64px;width:100%}md-toolbar._md-toolbar-transitions{-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-timing-function:cubic-bezier(.35,0,.25,1);transition-timing-function:cubic-bezier(.35,0,.25,1);-webkit-transition-property:background-color,fill,color;transition-property:background-color,fill,color}md-toolbar.md-whiteframe-z1-add,md-toolbar.md-whiteframe-z1-remove{-webkit-transition:box-shadow .5s linear;transition:box-shadow .5s linear}md-toolbar md-toolbar-filler{width:72px}md-toolbar *,md-toolbar :after,md-toolbar :before{box-sizing:border-box}md-toolbar.ng-animate{-webkit-transition:none;transition:none}md-toolbar.md-tall{height:128px;min-height:128px;max-height:128px}md-toolbar.md-medium-tall{height:88px;min-height:88px;max-height:88px}md-toolbar.md-medium-tall .md-toolbar-tools{height:48px;min-height:48px;max-height:48px}md-toolbar>.md-indent{margin-left:64px}[dir=rtl] md-toolbar>.md-indent{margin-left:auto;margin-right:64px}md-toolbar~md-content>md-list{padding:0}md-toolbar~md-content>md-list md-list-item:last-child md-divider{display:none}.md-toolbar-tools{font-size:20px;letter-spacing:.005em;box-sizing:border-box;font-weight:400;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row;width:100%;height:64px;max-height:64px;padding:0 16px;margin:0}.md-toolbar-tools h1,.md-toolbar-tools h2,.md-toolbar-tools h3{font-size:inherit;font-weight:inherit;margin:inherit}.md-toolbar-tools a{color:inherit;text-decoration:none}.md-toolbar-tools .fill-height{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.md-toolbar-tools md-checkbox{margin:inherit}.md-toolbar-tools .md-button{margin-top:0;margin-bottom:0}.md-toolbar-tools .md-button,.md-toolbar-tools .md-button.md-icon-button md-icon{-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-timing-function:cubic-bezier(.35,0,.25,1);transition-timing-function:cubic-bezier(.35,0,.25,1);-webkit-transition-property:background-color,fill,color;transition-property:background-color,fill,color}.md-toolbar-tools .md-button.md-icon-button md-icon.ng-animate,.md-toolbar-tools .md-button.ng-animate{-webkit-transition:none;transition:none}.md-toolbar-tools>.md-button:first-child{margin-left:-8px}[dir=rtl] .md-toolbar-tools>.md-button:first-child{margin-left:auto;margin-right:-8px}.md-toolbar-tools>.md-button:last-child{margin-right:-8px}[dir=rtl] .md-toolbar-tools>.md-button:last-child{margin-right:auto;margin-left:-8px}.md-toolbar-tools>md-menu:last-child{margin-right:-8px}[dir=rtl] .md-toolbar-tools>md-menu:last-child{margin-right:auto;margin-left:-8px}.md-toolbar-tools>md-menu:last-child>.md-button{margin-right:0}[dir=rtl] .md-toolbar-tools>md-menu:last-child>.md-button{margin-right:auto;margin-left:0}@media screen and (-ms-high-contrast:active){.md-toolbar-tools{border-bottom:1px solid #fff}}@media (min-width:0) and (max-width:959px) and (orientation:portrait){md-toolbar{min-height:56px}.md-toolbar-tools{height:56px;max-height:56px}}@media (min-width:0) and (max-width:959px) and (orientation:landscape){md-toolbar{min-height:48px}.md-toolbar-tools{height:48px;max-height:48px}}.md-toast-text{padding:0 6px}md-toast{position:absolute;z-index:105;box-sizing:border-box;cursor:default;padding:8px;opacity:1}md-toast,md-toast .md-toast-content{overflow:hidden;-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1)}md-toast .md-toast-content{display:-webkit-box;display:-webkit-flex;display:flex;direction:row;-webkit-box-align:center;-webkit-align-items:center;align-items:center;max-height:168px;max-width:100%;min-height:48px;padding:0 18px;box-shadow:0 2px 5px 0 rgba(0,0,0,.26);border-radius:2px;font-size:14px;-webkit-transform:translate3d(0,0,0) rotateZ(0deg);transform:translate3d(0,0,0) rotateZ(0deg);-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}md-toast .md-toast-content:before{content:"";min-height:48px;visibility:hidden;display:inline-block}[dir=rtl] md-toast .md-toast-content{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}md-toast .md-toast-content span{-webkit-box-flex:1;-webkit-flex:1 1 0%;flex:1 1 0%;box-sizing:border-box;min-width:0}md-toast.md-capsule,md-toast.md-capsule .md-toast-content{border-radius:24px}md-toast.ng-leave-active .md-toast-content{-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2)}md-toast.md-swipedown .md-toast-content,md-toast.md-swipeleft .md-toast-content,md-toast.md-swiperight .md-toast-content,md-toast.md-swipeup .md-toast-content{-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1)}md-toast.ng-enter{opacity:0}md-toast.ng-enter .md-toast-content{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}md-toast.ng-enter.md-top .md-toast-content{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}md-toast.ng-enter.ng-enter-active{opacity:1}md-toast.ng-enter.ng-enter-active .md-toast-content{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}md-toast.ng-leave.ng-leave-active .md-toast-content{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}md-toast.ng-leave.ng-leave-active.md-swipeup .md-toast-content{-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0)}md-toast.ng-leave.ng-leave-active.md-swipedown .md-toast-content{-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}md-toast.ng-leave.ng-leave-active.md-top .md-toast-content{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}md-toast .md-action{line-height:19px;margin-left:24px;margin-right:0;cursor:pointer;text-transform:uppercase;float:right}md-toast .md-button{min-width:0;margin-right:0;margin-left:12px}[dir=rtl] md-toast .md-button{margin-right:12px;margin-left:0}@media (max-width:959px){md-toast{left:0;right:0;width:100%;max-width:100%;min-width:0;border-radius:0;bottom:0;padding:0}md-toast.ng-leave.ng-leave-active.md-swipeup .md-toast-content{-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0)}md-toast.ng-leave.ng-leave-active.md-swipedown .md-toast-content{-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}}@media (min-width:960px){md-toast{min-width:304px}md-toast.md-bottom{bottom:0}md-toast.md-left{left:0}md-toast.md-right{right:0}md-toast.md-top{top:0}md-toast._md-start{left:0}[dir=rtl] md-toast._md-start{left:auto;right:0}md-toast._md-end{right:0}[dir=rtl] md-toast._md-end{right:auto;left:0}md-toast.ng-leave.ng-leave-active.md-swipeleft .md-toast-content{-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0)}md-toast.ng-leave.ng-leave-active.md-swiperight .md-toast-content{-webkit-transform:translate3d(50%,0,0);transform:translate3d(50%,0,0)}}@media (min-width:1920px){md-toast .md-toast-content{max-width:568px}}@media screen and (-ms-high-contrast:active){md-toast{border:1px solid #fff}}.md-toast-animating{overflow:hidden!important}.md-truncate{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.md-truncate.md-clip{text-overflow:clip}.md-truncate.flex{width:0}.md-virtual-repeat-container{box-sizing:border-box;display:block;margin:0;overflow:hidden;padding:0;position:relative}.md-virtual-repeat-container .md-virtual-repeat-scroller{bottom:0;box-sizing:border-box;left:0;margin:0;overflow-x:hidden;padding:0;position:absolute;right:0;top:0;-webkit-overflow-scrolling:touch}.md-virtual-repeat-container .md-virtual-repeat-sizer{box-sizing:border-box;height:1px;display:block;margin:0;padding:0;width:1px}.md-virtual-repeat-container .md-virtual-repeat-offsetter{box-sizing:border-box;left:0;margin:0;padding:0;position:absolute;right:0;top:0}.md-virtual-repeat-container.md-orient-horizontal .md-virtual-repeat-scroller{overflow-x:auto;overflow-y:hidden}.md-virtual-repeat-container.md-orient-horizontal .md-virtual-repeat-offsetter{bottom:16px;right:auto;white-space:nowrap}[dir=rtl] .md-virtual-repeat-container.md-orient-horizontal .md-virtual-repeat-offsetter{right:auto;left:auto}.md-whiteframe-1dp,.md-whiteframe-z1{box-shadow:0 1px 3px 0 rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12)}.md-whiteframe-2dp{box-shadow:0 1px 5px 0 rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}.md-whiteframe-3dp{box-shadow:0 1px 8px 0 rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 3px 3px -2px rgba(0,0,0,.12)}.md-whiteframe-4dp,.md-whiteframe-z2{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}.md-whiteframe-5dp{box-shadow:0 3px 5px -1px rgba(0,0,0,.2),0 5px 8px 0 rgba(0,0,0,.14),0 1px 14px 0 rgba(0,0,0,.12)}.md-whiteframe-6dp{box-shadow:0 3px 5px -1px rgba(0,0,0,.2),0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12)}.md-whiteframe-7dp,.md-whiteframe-z3{box-shadow:0 4px 5px -2px rgba(0,0,0,.2),0 7px 10px 1px rgba(0,0,0,.14),0 2px 16px 1px rgba(0,0,0,.12)}.md-whiteframe-8dp{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.md-whiteframe-9dp{box-shadow:0 5px 6px -3px rgba(0,0,0,.2),0 9px 12px 1px rgba(0,0,0,.14),0 3px 16px 2px rgba(0,0,0,.12)}.md-whiteframe-10dp,.md-whiteframe-z4{box-shadow:0 6px 6px -3px rgba(0,0,0,.2),0 10px 14px 1px rgba(0,0,0,.14),0 4px 18px 3px rgba(0,0,0,.12)}.md-whiteframe-11dp{box-shadow:0 6px 7px -4px rgba(0,0,0,.2),0 11px 15px 1px rgba(0,0,0,.14),0 4px 20px 3px rgba(0,0,0,.12)}.md-whiteframe-12dp{box-shadow:0 7px 8px -4px rgba(0,0,0,.2),0 12px 17px 2px rgba(0,0,0,.14),0 5px 22px 4px rgba(0,0,0,.12)}.md-whiteframe-13dp,.md-whiteframe-z5{box-shadow:0 7px 8px -4px rgba(0,0,0,.2),0 13px 19px 2px rgba(0,0,0,.14),0 5px 24px 4px rgba(0,0,0,.12)}.md-whiteframe-14dp{box-shadow:0 7px 9px -4px rgba(0,0,0,.2),0 14px 21px 2px rgba(0,0,0,.14),0 5px 26px 4px rgba(0,0,0,.12)}.md-whiteframe-15dp{box-shadow:0 8px 9px -5px rgba(0,0,0,.2),0 15px 22px 2px rgba(0,0,0,.14),0 6px 28px 5px rgba(0,0,0,.12)}.md-whiteframe-16dp{box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12)}.md-whiteframe-17dp{box-shadow:0 8px 11px -5px rgba(0,0,0,.2),0 17px 26px 2px rgba(0,0,0,.14),0 6px 32px 5px rgba(0,0,0,.12)}.md-whiteframe-18dp{box-shadow:0 9px 11px -5px rgba(0,0,0,.2),0 18px 28px 2px rgba(0,0,0,.14),0 7px 34px 6px rgba(0,0,0,.12)}.md-whiteframe-19dp{box-shadow:0 9px 12px -6px rgba(0,0,0,.2),0 19px 29px 2px rgba(0,0,0,.14),0 7px 36px 6px rgba(0,0,0,.12)}.md-whiteframe-20dp{box-shadow:0 10px 13px -6px rgba(0,0,0,.2),0 20px 31px 3px rgba(0,0,0,.14),0 8px 38px 7px rgba(0,0,0,.12)}.md-whiteframe-21dp{box-shadow:0 10px 13px -6px rgba(0,0,0,.2),0 21px 33px 3px rgba(0,0,0,.14),0 8px 40px 7px rgba(0,0,0,.12)}.md-whiteframe-22dp{box-shadow:0 10px 14px -6px rgba(0,0,0,.2),0 22px 35px 3px rgba(0,0,0,.14),0 8px 42px 7px rgba(0,0,0,.12)}.md-whiteframe-23dp{box-shadow:0 11px 14px -7px rgba(0,0,0,.2),0 23px 36px 3px rgba(0,0,0,.14),0 9px 44px 8px rgba(0,0,0,.12)}.md-whiteframe-24dp{box-shadow:0 11px 15px -7px rgba(0,0,0,.2),0 24px 38px 3px rgba(0,0,0,.14),0 9px 46px 8px rgba(0,0,0,.12)}@media screen and (-ms-high-contrast:active){md-whiteframe{border:1px solid #fff}}@media print{[md-whiteframe],md-whiteframe{background-color:#fff}}.ng-cloak,.x-ng-cloak,[data-ng-cloak],[ng-cloak],[ng\:cloak],[x-ng-cloak]{display:none!important}@-moz-document url-prefix(){.layout-fill{margin:0;width:100%;min-height:100%;height:100%}}.flex-order{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-0,.offset-0{margin-left:0}[dir=rtl] .flex-offset-0,[dir=rtl] .offset-0{margin-left:auto;margin-right:0}.flex-offset-5,.offset-5{margin-left:5%}[dir=rtl] .flex-offset-5,[dir=rtl] .offset-5{margin-left:auto;margin-right:5%}.flex-offset-10,.offset-10{margin-left:10%}[dir=rtl] .flex-offset-10,[dir=rtl] .offset-10{margin-left:auto;margin-right:10%}.flex-offset-15,.offset-15{margin-left:15%}[dir=rtl] .flex-offset-15,[dir=rtl] .offset-15{margin-left:auto;margin-right:15%}.flex-offset-20,.offset-20{margin-left:20%}[dir=rtl] .flex-offset-20,[dir=rtl] .offset-20{margin-left:auto;margin-right:20%}.flex-offset-25,.offset-25{margin-left:25%}[dir=rtl] .flex-offset-25,[dir=rtl] .offset-25{margin-left:auto;margin-right:25%}.flex-offset-30,.offset-30{margin-left:30%}[dir=rtl] .flex-offset-30,[dir=rtl] .offset-30{margin-left:auto;margin-right:30%}.flex-offset-35,.offset-35{margin-left:35%}[dir=rtl] .flex-offset-35,[dir=rtl] .offset-35{margin-left:auto;margin-right:35%}.flex-offset-40,.offset-40{margin-left:40%}[dir=rtl] .flex-offset-40,[dir=rtl] .offset-40{margin-left:auto;margin-right:40%}.flex-offset-45,.offset-45{margin-left:45%}[dir=rtl] .flex-offset-45,[dir=rtl] .offset-45{margin-left:auto;margin-right:45%}.flex-offset-50,.offset-50{margin-left:50%}[dir=rtl] .flex-offset-50,[dir=rtl] .offset-50{margin-left:auto;margin-right:50%}.flex-offset-55,.offset-55{margin-left:55%}[dir=rtl] .flex-offset-55,[dir=rtl] .offset-55{margin-left:auto;margin-right:55%}.flex-offset-60,.offset-60{margin-left:60%}[dir=rtl] .flex-offset-60,[dir=rtl] .offset-60{margin-left:auto;margin-right:60%}.flex-offset-65,.offset-65{margin-left:65%}[dir=rtl] .flex-offset-65,[dir=rtl] .offset-65{margin-left:auto;margin-right:65%}.flex-offset-70,.offset-70{margin-left:70%}[dir=rtl] .flex-offset-70,[dir=rtl] .offset-70{margin-left:auto;margin-right:70%}.flex-offset-75,.offset-75{margin-left:75%}[dir=rtl] .flex-offset-75,[dir=rtl] .offset-75{margin-left:auto;margin-right:75%}.flex-offset-80,.offset-80{margin-left:80%}[dir=rtl] .flex-offset-80,[dir=rtl] .offset-80{margin-left:auto;margin-right:80%}.flex-offset-85,.offset-85{margin-left:85%}[dir=rtl] .flex-offset-85,[dir=rtl] .offset-85{margin-left:auto;margin-right:85%}.flex-offset-90,.offset-90{margin-left:90%}[dir=rtl] .flex-offset-90,[dir=rtl] .offset-90{margin-left:auto;margin-right:90%}.flex-offset-95,.offset-95{margin-left:95%}[dir=rtl] .flex-offset-95,[dir=rtl] .offset-95{margin-left:auto;margin-right:95%}.flex-offset-33,.offset-33{margin-left:33.33333%}.flex-offset-66,.offset-66{margin-left:66.66667%}[dir=rtl] .flex-offset-66,[dir=rtl] .offset-66{margin-left:auto;margin-right:66.66667%}.layout-align,.layout-align-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align,.layout-align-start,.layout-align-start-center,.layout-align-start-end,.layout-align-start-start,.layout-align-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-center,.layout-align-center-center,.layout-align-center-end,.layout-align-center-start,.layout-align-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-end,.layout-align-end-center,.layout-align-end-end,.layout-align-end-start,.layout-align-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-space-around,.layout-align-space-around-center,.layout-align-space-around-end,.layout-align-space-around-start,.layout-align-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-space-between,.layout-align-space-between-center,.layout-align-space-between-end,.layout-align-space-between-start,.layout-align-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-center-start,.layout-align-end-start,.layout-align-space-around-start,.layout-align-space-between-start,.layout-align-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-center-center,.layout-align-end-center,.layout-align-space-around-center,.layout-align-space-between-center,.layout-align-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-center-center>*,.layout-align-end-center>*,.layout-align-space-around-center>*,.layout-align-space-between-center>*,.layout-align-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-center-end,.layout-align-end-end,.layout-align-space-around-end,.layout-align-space-between-end,.layout-align-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-center-stretch,.layout-align-end-stretch,.layout-align-space-around-stretch,.layout-align-space-between-stretch,.layout-align-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex{-webkit-flex:1;flex:1}.flex,.flex-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-0{max-width:0;max-height:100%}.flex-0,.layout-column>.flex-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-0{max-width:100%;max-height:0%}.layout-row>.flex-0{max-width:0;max-height:100%;min-width:0}.layout-column>.flex-0,.layout-row>.flex-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-0{max-width:100%;max-height:0%;min-height:0}.flex-5,.layout-row>.flex-5{max-width:5%;max-height:100%}.flex-5,.layout-column>.flex-5,.layout-row>.flex-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-5{max-width:100%;max-height:5%}.flex-10,.layout-row>.flex-10{max-width:10%;max-height:100%}.flex-10,.layout-column>.flex-10,.layout-row>.flex-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-10{max-width:100%;max-height:10%}.flex-15,.layout-row>.flex-15{max-width:15%;max-height:100%}.flex-15,.layout-column>.flex-15,.layout-row>.flex-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-15{max-width:100%;max-height:15%}.flex-20,.layout-row>.flex-20{max-width:20%;max-height:100%}.flex-20,.layout-column>.flex-20,.layout-row>.flex-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-20{max-width:100%;max-height:20%}.flex-25,.layout-row>.flex-25{max-width:25%;max-height:100%}.flex-25,.layout-column>.flex-25,.layout-row>.flex-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-25{max-width:100%;max-height:25%}.flex-30,.layout-row>.flex-30{max-width:30%;max-height:100%}.flex-30,.layout-column>.flex-30,.layout-row>.flex-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-30{max-width:100%;max-height:30%}.flex-35,.layout-row>.flex-35{max-width:35%;max-height:100%}.flex-35,.layout-column>.flex-35,.layout-row>.flex-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-35{max-width:100%;max-height:35%}.flex-40,.layout-row>.flex-40{max-width:40%;max-height:100%}.flex-40,.layout-column>.flex-40,.layout-row>.flex-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-40{max-width:100%;max-height:40%}.flex-45,.layout-row>.flex-45{max-width:45%;max-height:100%}.flex-45,.layout-column>.flex-45,.layout-row>.flex-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-45{max-width:100%;max-height:45%}.flex-50,.layout-row>.flex-50{max-width:50%;max-height:100%}.flex-50,.layout-column>.flex-50,.layout-row>.flex-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-50{max-width:100%;max-height:50%}.flex-55,.layout-row>.flex-55{max-width:55%;max-height:100%}.flex-55,.layout-column>.flex-55,.layout-row>.flex-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-55{max-width:100%;max-height:55%}.flex-60,.layout-row>.flex-60{max-width:60%;max-height:100%}.flex-60,.layout-column>.flex-60,.layout-row>.flex-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-60{max-width:100%;max-height:60%}.flex-65,.layout-row>.flex-65{max-width:65%;max-height:100%}.flex-65,.layout-column>.flex-65,.layout-row>.flex-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-65{max-width:100%;max-height:65%}.flex-70,.layout-row>.flex-70{max-width:70%;max-height:100%}.flex-70,.layout-column>.flex-70,.layout-row>.flex-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-70{max-width:100%;max-height:70%}.flex-75,.layout-row>.flex-75{max-width:75%;max-height:100%}.flex-75,.layout-column>.flex-75,.layout-row>.flex-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-75{max-width:100%;max-height:75%}.flex-80,.layout-row>.flex-80{max-width:80%;max-height:100%}.flex-80,.layout-column>.flex-80,.layout-row>.flex-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-80{max-width:100%;max-height:80%}.flex-85,.layout-row>.flex-85{max-width:85%;max-height:100%}.flex-85,.layout-column>.flex-85,.layout-row>.flex-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-85{max-width:100%;max-height:85%}.flex-90,.layout-row>.flex-90{max-width:90%;max-height:100%}.flex-90,.layout-column>.flex-90,.layout-row>.flex-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-90{max-width:100%;max-height:90%}.flex-95,.layout-row>.flex-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-column>.flex-95{max-height:95%}.flex-100,.layout-column>.flex-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-100{max-height:100%}.layout-row>.flex-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-column>.flex-100,.layout-row>.flex-100{max-width:100%}.layout-column>.flex-100,.layout-row>.flex-33,.layout-row>.flex-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-33{max-width:33.33%}.layout-row>.flex-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-row>.flex{min-width:0}.layout-column>.flex-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-column>.flex{min-height:0}.layout,.layout-column,.layout-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-column{-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}.layout-column,.layout-row{-webkit-box-direction:normal}.layout-row{-webkit-box-orient:horizontal;-webkit-flex-direction:row;flex-direction:row}.layout-padding-sm>*,.layout-padding>.flex-sm{padding:4px}.layout-padding,.layout-padding-gt-sm,.layout-padding-gt-sm>*,.layout-padding-md,.layout-padding-md>*,.layout-padding>*,.layout-padding>.flex,.layout-padding>.flex-gt-sm,.layout-padding>.flex-md{padding:8px}.layout-padding-gt-lg>*,.layout-padding-gt-md>*,.layout-padding-lg>*,.layout-padding>.flex-gt-lg,.layout-padding>.flex-gt-md,.layout-padding>.flex-lg{padding:16px}.layout-margin-sm>*,.layout-margin>.flex-sm{margin:4px}.layout-margin,.layout-margin-gt-sm,.layout-margin-gt-sm>*,.layout-margin-md,.layout-margin-md>*,.layout-margin>*,.layout-margin>.flex,.layout-margin>.flex-gt-sm,.layout-margin>.flex-md{margin:8px}.layout-margin-gt-lg>*,.layout-margin-gt-md>*,.layout-margin-lg>*,.layout-margin>.flex-gt-lg,.layout-margin>.flex-gt-md,.layout-margin>.flex-lg{margin:16px}.layout-wrap{-webkit-flex-wrap:wrap;flex-wrap:wrap}.layout-nowrap{-webkit-flex-wrap:nowrap;flex-wrap:nowrap}.layout-fill{margin:0;width:100%;min-height:100%;height:100%}@media (max-width:599px){.hide-xs:not(.show-xs):not(.show),.hide:not(.show-xs):not(.show){display:none}.flex-order-xs--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order-xs--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order-xs--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order-xs--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order-xs--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order-xs--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order-xs--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order-xs--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order-xs--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order-xs--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order-xs--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order-xs--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order-xs--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order-xs--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order-xs--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order-xs--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order-xs--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order-xs--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order-xs--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order-xs--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-xs-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-xs-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-xs-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-xs-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-xs-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-xs-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-xs-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-xs-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-xs-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-xs-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-xs-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-xs-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-xs-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-xs-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-xs-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-xs-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-xs-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-xs-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-xs-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-xs-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-xs-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-xs-0,.offset-xs-0{margin-left:0}[dir=rtl] .flex-offset-xs-0,[dir=rtl] .offset-xs-0{margin-left:auto;margin-right:0}.flex-offset-xs-5,.offset-xs-5{margin-left:5%}[dir=rtl] .flex-offset-xs-5,[dir=rtl] .offset-xs-5{margin-left:auto;margin-right:5%}.flex-offset-xs-10,.offset-xs-10{margin-left:10%}[dir=rtl] .flex-offset-xs-10,[dir=rtl] .offset-xs-10{margin-left:auto;margin-right:10%}.flex-offset-xs-15,.offset-xs-15{margin-left:15%}[dir=rtl] .flex-offset-xs-15,[dir=rtl] .offset-xs-15{margin-left:auto;margin-right:15%}.flex-offset-xs-20,.offset-xs-20{margin-left:20%}[dir=rtl] .flex-offset-xs-20,[dir=rtl] .offset-xs-20{margin-left:auto;margin-right:20%}.flex-offset-xs-25,.offset-xs-25{margin-left:25%}[dir=rtl] .flex-offset-xs-25,[dir=rtl] .offset-xs-25{margin-left:auto;margin-right:25%}.flex-offset-xs-30,.offset-xs-30{margin-left:30%}[dir=rtl] .flex-offset-xs-30,[dir=rtl] .offset-xs-30{margin-left:auto;margin-right:30%}.flex-offset-xs-35,.offset-xs-35{margin-left:35%}[dir=rtl] .flex-offset-xs-35,[dir=rtl] .offset-xs-35{margin-left:auto;margin-right:35%}.flex-offset-xs-40,.offset-xs-40{margin-left:40%}[dir=rtl] .flex-offset-xs-40,[dir=rtl] .offset-xs-40{margin-left:auto;margin-right:40%}.flex-offset-xs-45,.offset-xs-45{margin-left:45%}[dir=rtl] .flex-offset-xs-45,[dir=rtl] .offset-xs-45{margin-left:auto;margin-right:45%}.flex-offset-xs-50,.offset-xs-50{margin-left:50%}[dir=rtl] .flex-offset-xs-50,[dir=rtl] .offset-xs-50{margin-left:auto;margin-right:50%}.flex-offset-xs-55,.offset-xs-55{margin-left:55%}[dir=rtl] .flex-offset-xs-55,[dir=rtl] .offset-xs-55{margin-left:auto;margin-right:55%}.flex-offset-xs-60,.offset-xs-60{margin-left:60%}[dir=rtl] .flex-offset-xs-60,[dir=rtl] .offset-xs-60{margin-left:auto;margin-right:60%}.flex-offset-xs-65,.offset-xs-65{margin-left:65%}[dir=rtl] .flex-offset-xs-65,[dir=rtl] .offset-xs-65{margin-left:auto;margin-right:65%}.flex-offset-xs-70,.offset-xs-70{margin-left:70%}[dir=rtl] .flex-offset-xs-70,[dir=rtl] .offset-xs-70{margin-left:auto;margin-right:70%}.flex-offset-xs-75,.offset-xs-75{margin-left:75%}[dir=rtl] .flex-offset-xs-75,[dir=rtl] .offset-xs-75{margin-left:auto;margin-right:75%}.flex-offset-xs-80,.offset-xs-80{margin-left:80%}[dir=rtl] .flex-offset-xs-80,[dir=rtl] .offset-xs-80{margin-left:auto;margin-right:80%}.flex-offset-xs-85,.offset-xs-85{margin-left:85%}[dir=rtl] .flex-offset-xs-85,[dir=rtl] .offset-xs-85{margin-left:auto;margin-right:85%}.flex-offset-xs-90,.offset-xs-90{margin-left:90%}[dir=rtl] .flex-offset-xs-90,[dir=rtl] .offset-xs-90{margin-left:auto;margin-right:90%}.flex-offset-xs-95,.offset-xs-95{margin-left:95%}[dir=rtl] .flex-offset-xs-95,[dir=rtl] .offset-xs-95{margin-left:auto;margin-right:95%}.flex-offset-xs-33,.offset-xs-33{margin-left:33.33333%}.flex-offset-xs-66,.offset-xs-66{margin-left:66.66667%}[dir=rtl] .flex-offset-xs-66,[dir=rtl] .offset-xs-66{margin-left:auto;margin-right:66.66667%}.layout-align-xs,.layout-align-xs-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align-xs,.layout-align-xs-start,.layout-align-xs-start-center,.layout-align-xs-start-end,.layout-align-xs-start-start,.layout-align-xs-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-xs-center,.layout-align-xs-center-center,.layout-align-xs-center-end,.layout-align-xs-center-start,.layout-align-xs-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-xs-end,.layout-align-xs-end-center,.layout-align-xs-end-end,.layout-align-xs-end-start,.layout-align-xs-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-xs-space-around,.layout-align-xs-space-around-center,.layout-align-xs-space-around-end,.layout-align-xs-space-around-start,.layout-align-xs-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-xs-space-between,.layout-align-xs-space-between-center,.layout-align-xs-space-between-end,.layout-align-xs-space-between-start,.layout-align-xs-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-xs-center-start,.layout-align-xs-end-start,.layout-align-xs-space-around-start,.layout-align-xs-space-between-start,.layout-align-xs-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-xs-center-center,.layout-align-xs-end-center,.layout-align-xs-space-around-center,.layout-align-xs-space-between-center,.layout-align-xs-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-xs-center-center>*,.layout-align-xs-end-center>*,.layout-align-xs-space-around-center>*,.layout-align-xs-space-between-center>*,.layout-align-xs-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-xs-center-end,.layout-align-xs-end-end,.layout-align-xs-space-around-end,.layout-align-xs-space-between-end,.layout-align-xs-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-xs-center-stretch,.layout-align-xs-end-stretch,.layout-align-xs-space-around-stretch,.layout-align-xs-space-between-stretch,.layout-align-xs-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex-xs{-webkit-flex:1;flex:1}.flex-xs,.flex-xs-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-xs-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-xs-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-xs-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-xs-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-xs-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-xs-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-xs-0,.layout-row>.flex-xs-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:0;max-height:100%;box-sizing:border-box}.layout-row>.flex-xs-0{min-width:0}.layout-column>.flex-xs-0{max-width:100%;max-height:0%}.layout-column>.flex-xs-0,.layout-xs-row>.flex-xs-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-row>.flex-xs-0{max-width:0;max-height:100%;min-width:0}.layout-xs-column>.flex-xs-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:0%;box-sizing:border-box;min-height:0}.flex-xs-5,.layout-row>.flex-xs-5{max-width:5%;max-height:100%}.flex-xs-5,.layout-column>.flex-xs-5,.layout-row>.flex-xs-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-5{max-width:100%;max-height:5%}.layout-xs-row>.flex-xs-5{max-width:5%;max-height:100%}.layout-xs-column>.flex-xs-5,.layout-xs-row>.flex-xs-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-5{max-width:100%;max-height:5%}.flex-xs-10,.layout-row>.flex-xs-10{max-width:10%;max-height:100%}.flex-xs-10,.layout-column>.flex-xs-10,.layout-row>.flex-xs-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-10{max-width:100%;max-height:10%}.layout-xs-row>.flex-xs-10{max-width:10%;max-height:100%}.layout-xs-column>.flex-xs-10,.layout-xs-row>.flex-xs-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-10{max-width:100%;max-height:10%}.flex-xs-15,.layout-row>.flex-xs-15{max-width:15%;max-height:100%}.flex-xs-15,.layout-column>.flex-xs-15,.layout-row>.flex-xs-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-15{max-width:100%;max-height:15%}.layout-xs-row>.flex-xs-15{max-width:15%;max-height:100%}.layout-xs-column>.flex-xs-15,.layout-xs-row>.flex-xs-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-15{max-width:100%;max-height:15%}.flex-xs-20,.layout-row>.flex-xs-20{max-width:20%;max-height:100%}.flex-xs-20,.layout-column>.flex-xs-20,.layout-row>.flex-xs-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-20{max-width:100%;max-height:20%}.layout-xs-row>.flex-xs-20{max-width:20%;max-height:100%}.layout-xs-column>.flex-xs-20,.layout-xs-row>.flex-xs-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-20{max-width:100%;max-height:20%}.flex-xs-25,.layout-row>.flex-xs-25{max-width:25%;max-height:100%}.flex-xs-25,.layout-column>.flex-xs-25,.layout-row>.flex-xs-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-25{max-width:100%;max-height:25%}.layout-xs-row>.flex-xs-25{max-width:25%;max-height:100%}.layout-xs-column>.flex-xs-25,.layout-xs-row>.flex-xs-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-25{max-width:100%;max-height:25%}.flex-xs-30,.layout-row>.flex-xs-30{max-width:30%;max-height:100%}.flex-xs-30,.layout-column>.flex-xs-30,.layout-row>.flex-xs-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-30{max-width:100%;max-height:30%}.layout-xs-row>.flex-xs-30{max-width:30%;max-height:100%}.layout-xs-column>.flex-xs-30,.layout-xs-row>.flex-xs-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-30{max-width:100%;max-height:30%}.flex-xs-35,.layout-row>.flex-xs-35{max-width:35%;max-height:100%}.flex-xs-35,.layout-column>.flex-xs-35,.layout-row>.flex-xs-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-35{max-width:100%;max-height:35%}.layout-xs-row>.flex-xs-35{max-width:35%;max-height:100%}.layout-xs-column>.flex-xs-35,.layout-xs-row>.flex-xs-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-35{max-width:100%;max-height:35%}.flex-xs-40,.layout-row>.flex-xs-40{max-width:40%;max-height:100%}.flex-xs-40,.layout-column>.flex-xs-40,.layout-row>.flex-xs-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-40{max-width:100%;max-height:40%}.layout-xs-row>.flex-xs-40{max-width:40%;max-height:100%}.layout-xs-column>.flex-xs-40,.layout-xs-row>.flex-xs-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-40{max-width:100%;max-height:40%}.flex-xs-45,.layout-row>.flex-xs-45{max-width:45%;max-height:100%}.flex-xs-45,.layout-column>.flex-xs-45,.layout-row>.flex-xs-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-45{max-width:100%;max-height:45%}.layout-xs-row>.flex-xs-45{max-width:45%;max-height:100%}.layout-xs-column>.flex-xs-45,.layout-xs-row>.flex-xs-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-45{max-width:100%;max-height:45%}.flex-xs-50,.layout-row>.flex-xs-50{max-width:50%;max-height:100%}.flex-xs-50,.layout-column>.flex-xs-50,.layout-row>.flex-xs-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-50{max-width:100%;max-height:50%}.layout-xs-row>.flex-xs-50{max-width:50%;max-height:100%}.layout-xs-column>.flex-xs-50,.layout-xs-row>.flex-xs-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-50{max-width:100%;max-height:50%}.flex-xs-55,.layout-row>.flex-xs-55{max-width:55%;max-height:100%}.flex-xs-55,.layout-column>.flex-xs-55,.layout-row>.flex-xs-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-55{max-width:100%;max-height:55%}.layout-xs-row>.flex-xs-55{max-width:55%;max-height:100%}.layout-xs-column>.flex-xs-55,.layout-xs-row>.flex-xs-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-55{max-width:100%;max-height:55%}.flex-xs-60,.layout-row>.flex-xs-60{max-width:60%;max-height:100%}.flex-xs-60,.layout-column>.flex-xs-60,.layout-row>.flex-xs-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-60{max-width:100%;max-height:60%}.layout-xs-row>.flex-xs-60{max-width:60%;max-height:100%}.layout-xs-column>.flex-xs-60,.layout-xs-row>.flex-xs-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-60{max-width:100%;max-height:60%}.flex-xs-65,.layout-row>.flex-xs-65{max-width:65%;max-height:100%}.flex-xs-65,.layout-column>.flex-xs-65,.layout-row>.flex-xs-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-65{max-width:100%;max-height:65%}.layout-xs-row>.flex-xs-65{max-width:65%;max-height:100%}.layout-xs-column>.flex-xs-65,.layout-xs-row>.flex-xs-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-65{max-width:100%;max-height:65%}.flex-xs-70,.layout-row>.flex-xs-70{max-width:70%;max-height:100%}.flex-xs-70,.layout-column>.flex-xs-70,.layout-row>.flex-xs-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-70{max-width:100%;max-height:70%}.layout-xs-row>.flex-xs-70{max-width:70%;max-height:100%}.layout-xs-column>.flex-xs-70,.layout-xs-row>.flex-xs-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-70{max-width:100%;max-height:70%}.flex-xs-75,.layout-row>.flex-xs-75{max-width:75%;max-height:100%}.flex-xs-75,.layout-column>.flex-xs-75,.layout-row>.flex-xs-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-75{max-width:100%;max-height:75%}.layout-xs-row>.flex-xs-75{max-width:75%;max-height:100%}.layout-xs-column>.flex-xs-75,.layout-xs-row>.flex-xs-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-75{max-width:100%;max-height:75%}.flex-xs-80,.layout-row>.flex-xs-80{max-width:80%;max-height:100%}.flex-xs-80,.layout-column>.flex-xs-80,.layout-row>.flex-xs-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-80{max-width:100%;max-height:80%}.layout-xs-row>.flex-xs-80{max-width:80%;max-height:100%}.layout-xs-column>.flex-xs-80,.layout-xs-row>.flex-xs-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-80{max-width:100%;max-height:80%}.flex-xs-85,.layout-row>.flex-xs-85{max-width:85%;max-height:100%}.flex-xs-85,.layout-column>.flex-xs-85,.layout-row>.flex-xs-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-85{max-width:100%;max-height:85%}.layout-xs-row>.flex-xs-85{max-width:85%;max-height:100%}.layout-xs-column>.flex-xs-85,.layout-xs-row>.flex-xs-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-85{max-width:100%;max-height:85%}.flex-xs-90,.layout-row>.flex-xs-90{max-width:90%;max-height:100%}.flex-xs-90,.layout-column>.flex-xs-90,.layout-row>.flex-xs-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-90{max-width:100%;max-height:90%}.layout-xs-row>.flex-xs-90{max-width:90%;max-height:100%}.layout-xs-column>.flex-xs-90,.layout-xs-row>.flex-xs-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xs-column>.flex-xs-90{max-width:100%;max-height:90%}.flex-xs-95,.layout-row>.flex-xs-95{max-width:95%;max-height:100%}.flex-xs-95,.layout-column>.flex-xs-95,.layout-row>.flex-xs-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xs-95{max-width:100%;max-height:95%}.layout-xs-row>.flex-xs-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-xs-column>.flex-xs-95{max-height:95%}.flex-xs-100,.layout-xs-column>.flex-xs-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-xs-100{max-height:100%}.layout-column>.flex-xs-100,.layout-row>.flex-xs-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-xs-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-xs-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-xs-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-xs-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-xs-column>.flex-xs-100,.layout-xs-row>.flex-xs-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-xs-row>.flex-xs-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-xs-row>.flex-xs-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-xs-row>.flex{min-width:0}.layout-xs-column>.flex-xs-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-xs-column>.flex-xs-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-xs-column>.flex{min-height:0}.layout-xs,.layout-xs-column,.layout-xs-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-xs-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}.layout-xs-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}}@media (min-width:600px){.flex-order-gt-xs--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order-gt-xs--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order-gt-xs--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order-gt-xs--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order-gt-xs--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order-gt-xs--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order-gt-xs--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order-gt-xs--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order-gt-xs--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order-gt-xs--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order-gt-xs--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order-gt-xs--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order-gt-xs--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order-gt-xs--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order-gt-xs--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order-gt-xs--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order-gt-xs--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order-gt-xs--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order-gt-xs--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order-gt-xs--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-gt-xs-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-gt-xs-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-gt-xs-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-gt-xs-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-gt-xs-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-gt-xs-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-gt-xs-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-gt-xs-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-gt-xs-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-gt-xs-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-gt-xs-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-gt-xs-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-gt-xs-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-gt-xs-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-gt-xs-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-gt-xs-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-gt-xs-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-gt-xs-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-gt-xs-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-gt-xs-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-gt-xs-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-gt-xs-0,.offset-gt-xs-0{margin-left:0}[dir=rtl] .flex-offset-gt-xs-0,[dir=rtl] .offset-gt-xs-0{margin-left:auto;margin-right:0}.flex-offset-gt-xs-5,.offset-gt-xs-5{margin-left:5%}[dir=rtl] .flex-offset-gt-xs-5,[dir=rtl] .offset-gt-xs-5{margin-left:auto;margin-right:5%}.flex-offset-gt-xs-10,.offset-gt-xs-10{margin-left:10%}[dir=rtl] .flex-offset-gt-xs-10,[dir=rtl] .offset-gt-xs-10{margin-left:auto;margin-right:10%}.flex-offset-gt-xs-15,.offset-gt-xs-15{margin-left:15%}[dir=rtl] .flex-offset-gt-xs-15,[dir=rtl] .offset-gt-xs-15{margin-left:auto;margin-right:15%}.flex-offset-gt-xs-20,.offset-gt-xs-20{margin-left:20%}[dir=rtl] .flex-offset-gt-xs-20,[dir=rtl] .offset-gt-xs-20{margin-left:auto;margin-right:20%}.flex-offset-gt-xs-25,.offset-gt-xs-25{margin-left:25%}[dir=rtl] .flex-offset-gt-xs-25,[dir=rtl] .offset-gt-xs-25{margin-left:auto;margin-right:25%}.flex-offset-gt-xs-30,.offset-gt-xs-30{margin-left:30%}[dir=rtl] .flex-offset-gt-xs-30,[dir=rtl] .offset-gt-xs-30{margin-left:auto;margin-right:30%}.flex-offset-gt-xs-35,.offset-gt-xs-35{margin-left:35%}[dir=rtl] .flex-offset-gt-xs-35,[dir=rtl] .offset-gt-xs-35{margin-left:auto;margin-right:35%}.flex-offset-gt-xs-40,.offset-gt-xs-40{margin-left:40%}[dir=rtl] .flex-offset-gt-xs-40,[dir=rtl] .offset-gt-xs-40{margin-left:auto;margin-right:40%}.flex-offset-gt-xs-45,.offset-gt-xs-45{margin-left:45%}[dir=rtl] .flex-offset-gt-xs-45,[dir=rtl] .offset-gt-xs-45{margin-left:auto;margin-right:45%}.flex-offset-gt-xs-50,.offset-gt-xs-50{margin-left:50%}[dir=rtl] .flex-offset-gt-xs-50,[dir=rtl] .offset-gt-xs-50{margin-left:auto;margin-right:50%}.flex-offset-gt-xs-55,.offset-gt-xs-55{margin-left:55%}[dir=rtl] .flex-offset-gt-xs-55,[dir=rtl] .offset-gt-xs-55{margin-left:auto;margin-right:55%}.flex-offset-gt-xs-60,.offset-gt-xs-60{margin-left:60%}[dir=rtl] .flex-offset-gt-xs-60,[dir=rtl] .offset-gt-xs-60{margin-left:auto;margin-right:60%}.flex-offset-gt-xs-65,.offset-gt-xs-65{margin-left:65%}[dir=rtl] .flex-offset-gt-xs-65,[dir=rtl] .offset-gt-xs-65{margin-left:auto;margin-right:65%}.flex-offset-gt-xs-70,.offset-gt-xs-70{margin-left:70%}[dir=rtl] .flex-offset-gt-xs-70,[dir=rtl] .offset-gt-xs-70{margin-left:auto;margin-right:70%}.flex-offset-gt-xs-75,.offset-gt-xs-75{margin-left:75%}[dir=rtl] .flex-offset-gt-xs-75,[dir=rtl] .offset-gt-xs-75{margin-left:auto;margin-right:75%}.flex-offset-gt-xs-80,.offset-gt-xs-80{margin-left:80%}[dir=rtl] .flex-offset-gt-xs-80,[dir=rtl] .offset-gt-xs-80{margin-left:auto;margin-right:80%}.flex-offset-gt-xs-85,.offset-gt-xs-85{margin-left:85%}[dir=rtl] .flex-offset-gt-xs-85,[dir=rtl] .offset-gt-xs-85{margin-left:auto;margin-right:85%}.flex-offset-gt-xs-90,.offset-gt-xs-90{margin-left:90%}[dir=rtl] .flex-offset-gt-xs-90,[dir=rtl] .offset-gt-xs-90{margin-left:auto;margin-right:90%}.flex-offset-gt-xs-95,.offset-gt-xs-95{margin-left:95%}[dir=rtl] .flex-offset-gt-xs-95,[dir=rtl] .offset-gt-xs-95{margin-left:auto;margin-right:95%}.flex-offset-gt-xs-33,.offset-gt-xs-33{margin-left:33.33333%}.flex-offset-gt-xs-66,.offset-gt-xs-66{margin-left:66.66667%}[dir=rtl] .flex-offset-gt-xs-66,[dir=rtl] .offset-gt-xs-66{margin-left:auto;margin-right:66.66667%}.layout-align-gt-xs,.layout-align-gt-xs-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align-gt-xs,.layout-align-gt-xs-start,.layout-align-gt-xs-start-center,.layout-align-gt-xs-start-end,.layout-align-gt-xs-start-start,.layout-align-gt-xs-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-gt-xs-center,.layout-align-gt-xs-center-center,.layout-align-gt-xs-center-end,.layout-align-gt-xs-center-start,.layout-align-gt-xs-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-gt-xs-end,.layout-align-gt-xs-end-center,.layout-align-gt-xs-end-end,.layout-align-gt-xs-end-start,.layout-align-gt-xs-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-gt-xs-space-around,.layout-align-gt-xs-space-around-center,.layout-align-gt-xs-space-around-end,.layout-align-gt-xs-space-around-start,.layout-align-gt-xs-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-gt-xs-space-between,.layout-align-gt-xs-space-between-center,.layout-align-gt-xs-space-between-end,.layout-align-gt-xs-space-between-start,.layout-align-gt-xs-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-gt-xs-center-start,.layout-align-gt-xs-end-start,.layout-align-gt-xs-space-around-start,.layout-align-gt-xs-space-between-start,.layout-align-gt-xs-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-gt-xs-center-center,.layout-align-gt-xs-end-center,.layout-align-gt-xs-space-around-center,.layout-align-gt-xs-space-between-center,.layout-align-gt-xs-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-gt-xs-center-center>*,.layout-align-gt-xs-end-center>*,.layout-align-gt-xs-space-around-center>*,.layout-align-gt-xs-space-between-center>*,.layout-align-gt-xs-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-gt-xs-center-end,.layout-align-gt-xs-end-end,.layout-align-gt-xs-space-around-end,.layout-align-gt-xs-space-between-end,.layout-align-gt-xs-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-gt-xs-center-stretch,.layout-align-gt-xs-end-stretch,.layout-align-gt-xs-space-around-stretch,.layout-align-gt-xs-space-between-stretch,.layout-align-gt-xs-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex-gt-xs{-webkit-flex:1;flex:1}.flex-gt-xs,.flex-gt-xs-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-gt-xs-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-gt-xs-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-gt-xs-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-gt-xs-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-gt-xs-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-gt-xs-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-gt-xs-0,.layout-row>.flex-gt-xs-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:0;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-xs-0{min-width:0}.layout-column>.flex-gt-xs-0{max-width:100%;max-height:0%}.layout-column>.flex-gt-xs-0,.layout-gt-xs-row>.flex-gt-xs-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-row>.flex-gt-xs-0{max-width:0;max-height:100%;min-width:0}.layout-gt-xs-column>.flex-gt-xs-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:0%;box-sizing:border-box;min-height:0}.flex-gt-xs-5,.layout-row>.flex-gt-xs-5{max-width:5%;max-height:100%}.flex-gt-xs-5,.layout-column>.flex-gt-xs-5,.layout-row>.flex-gt-xs-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-5{max-width:100%;max-height:5%}.layout-gt-xs-row>.flex-gt-xs-5{max-width:5%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-5,.layout-gt-xs-row>.flex-gt-xs-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-5{max-width:100%;max-height:5%}.flex-gt-xs-10,.layout-row>.flex-gt-xs-10{max-width:10%;max-height:100%}.flex-gt-xs-10,.layout-column>.flex-gt-xs-10,.layout-row>.flex-gt-xs-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-10{max-width:100%;max-height:10%}.layout-gt-xs-row>.flex-gt-xs-10{max-width:10%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-10,.layout-gt-xs-row>.flex-gt-xs-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-10{max-width:100%;max-height:10%}.flex-gt-xs-15,.layout-row>.flex-gt-xs-15{max-width:15%;max-height:100%}.flex-gt-xs-15,.layout-column>.flex-gt-xs-15,.layout-row>.flex-gt-xs-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-15{max-width:100%;max-height:15%}.layout-gt-xs-row>.flex-gt-xs-15{max-width:15%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-15,.layout-gt-xs-row>.flex-gt-xs-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-15{max-width:100%;max-height:15%}.flex-gt-xs-20,.layout-row>.flex-gt-xs-20{max-width:20%;max-height:100%}.flex-gt-xs-20,.layout-column>.flex-gt-xs-20,.layout-row>.flex-gt-xs-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-20{max-width:100%;max-height:20%}.layout-gt-xs-row>.flex-gt-xs-20{max-width:20%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-20,.layout-gt-xs-row>.flex-gt-xs-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-20{max-width:100%;max-height:20%}.flex-gt-xs-25,.layout-row>.flex-gt-xs-25{max-width:25%;max-height:100%}.flex-gt-xs-25,.layout-column>.flex-gt-xs-25,.layout-row>.flex-gt-xs-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-25{max-width:100%;max-height:25%}.layout-gt-xs-row>.flex-gt-xs-25{max-width:25%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-25,.layout-gt-xs-row>.flex-gt-xs-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-25{max-width:100%;max-height:25%}.flex-gt-xs-30,.layout-row>.flex-gt-xs-30{max-width:30%;max-height:100%}.flex-gt-xs-30,.layout-column>.flex-gt-xs-30,.layout-row>.flex-gt-xs-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-30{max-width:100%;max-height:30%}.layout-gt-xs-row>.flex-gt-xs-30{max-width:30%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-30,.layout-gt-xs-row>.flex-gt-xs-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-30{max-width:100%;max-height:30%}.flex-gt-xs-35,.layout-row>.flex-gt-xs-35{max-width:35%;max-height:100%}.flex-gt-xs-35,.layout-column>.flex-gt-xs-35,.layout-row>.flex-gt-xs-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-35{max-width:100%;max-height:35%}.layout-gt-xs-row>.flex-gt-xs-35{max-width:35%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-35,.layout-gt-xs-row>.flex-gt-xs-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-35{max-width:100%;max-height:35%}.flex-gt-xs-40,.layout-row>.flex-gt-xs-40{max-width:40%;max-height:100%}.flex-gt-xs-40,.layout-column>.flex-gt-xs-40,.layout-row>.flex-gt-xs-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-40{max-width:100%;max-height:40%}.layout-gt-xs-row>.flex-gt-xs-40{max-width:40%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-40,.layout-gt-xs-row>.flex-gt-xs-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-40{max-width:100%;max-height:40%}.flex-gt-xs-45,.layout-row>.flex-gt-xs-45{max-width:45%;max-height:100%}.flex-gt-xs-45,.layout-column>.flex-gt-xs-45,.layout-row>.flex-gt-xs-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-45{max-width:100%;max-height:45%}.layout-gt-xs-row>.flex-gt-xs-45{max-width:45%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-45,.layout-gt-xs-row>.flex-gt-xs-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-45{max-width:100%;max-height:45%}.flex-gt-xs-50,.layout-row>.flex-gt-xs-50{max-width:50%;max-height:100%}.flex-gt-xs-50,.layout-column>.flex-gt-xs-50,.layout-row>.flex-gt-xs-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-50{max-width:100%;max-height:50%}.layout-gt-xs-row>.flex-gt-xs-50{max-width:50%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-50,.layout-gt-xs-row>.flex-gt-xs-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-50{max-width:100%;max-height:50%}.flex-gt-xs-55,.layout-row>.flex-gt-xs-55{max-width:55%;max-height:100%}.flex-gt-xs-55,.layout-column>.flex-gt-xs-55,.layout-row>.flex-gt-xs-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-55{max-width:100%;max-height:55%}.layout-gt-xs-row>.flex-gt-xs-55{max-width:55%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-55,.layout-gt-xs-row>.flex-gt-xs-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-55{max-width:100%;max-height:55%}.flex-gt-xs-60,.layout-row>.flex-gt-xs-60{max-width:60%;max-height:100%}.flex-gt-xs-60,.layout-column>.flex-gt-xs-60,.layout-row>.flex-gt-xs-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-60{max-width:100%;max-height:60%}.layout-gt-xs-row>.flex-gt-xs-60{max-width:60%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-60,.layout-gt-xs-row>.flex-gt-xs-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-60{max-width:100%;max-height:60%}.flex-gt-xs-65,.layout-row>.flex-gt-xs-65{max-width:65%;max-height:100%}.flex-gt-xs-65,.layout-column>.flex-gt-xs-65,.layout-row>.flex-gt-xs-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-65{max-width:100%;max-height:65%}.layout-gt-xs-row>.flex-gt-xs-65{max-width:65%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-65,.layout-gt-xs-row>.flex-gt-xs-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-65{max-width:100%;max-height:65%}.flex-gt-xs-70,.layout-row>.flex-gt-xs-70{max-width:70%;max-height:100%}.flex-gt-xs-70,.layout-column>.flex-gt-xs-70,.layout-row>.flex-gt-xs-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-70{max-width:100%;max-height:70%}.layout-gt-xs-row>.flex-gt-xs-70{max-width:70%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-70,.layout-gt-xs-row>.flex-gt-xs-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-70{max-width:100%;max-height:70%}.flex-gt-xs-75,.layout-row>.flex-gt-xs-75{max-width:75%;max-height:100%}.flex-gt-xs-75,.layout-column>.flex-gt-xs-75,.layout-row>.flex-gt-xs-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-75{max-width:100%;max-height:75%}.layout-gt-xs-row>.flex-gt-xs-75{max-width:75%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-75,.layout-gt-xs-row>.flex-gt-xs-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-75{max-width:100%;max-height:75%}.flex-gt-xs-80,.layout-row>.flex-gt-xs-80{max-width:80%;max-height:100%}.flex-gt-xs-80,.layout-column>.flex-gt-xs-80,.layout-row>.flex-gt-xs-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-80{max-width:100%;max-height:80%}.layout-gt-xs-row>.flex-gt-xs-80{max-width:80%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-80,.layout-gt-xs-row>.flex-gt-xs-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-80{max-width:100%;max-height:80%}.flex-gt-xs-85,.layout-row>.flex-gt-xs-85{max-width:85%;max-height:100%}.flex-gt-xs-85,.layout-column>.flex-gt-xs-85,.layout-row>.flex-gt-xs-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-85{max-width:100%;max-height:85%}.layout-gt-xs-row>.flex-gt-xs-85{max-width:85%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-85,.layout-gt-xs-row>.flex-gt-xs-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-85{max-width:100%;max-height:85%}.flex-gt-xs-90,.layout-row>.flex-gt-xs-90{max-width:90%;max-height:100%}.flex-gt-xs-90,.layout-column>.flex-gt-xs-90,.layout-row>.flex-gt-xs-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-90{max-width:100%;max-height:90%}.layout-gt-xs-row>.flex-gt-xs-90{max-width:90%;max-height:100%}.layout-gt-xs-column>.flex-gt-xs-90,.layout-gt-xs-row>.flex-gt-xs-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-90{max-width:100%;max-height:90%}.flex-gt-xs-95,.layout-row>.flex-gt-xs-95{max-width:95%;max-height:100%}.flex-gt-xs-95,.layout-column>.flex-gt-xs-95,.layout-row>.flex-gt-xs-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-xs-95{max-width:100%;max-height:95%}.layout-gt-xs-row>.flex-gt-xs-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-95{max-height:95%}.flex-gt-xs-100,.layout-gt-xs-column>.flex-gt-xs-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-gt-xs-100{max-height:100%}.layout-column>.flex-gt-xs-100,.layout-row>.flex-gt-xs-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-xs-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-xs-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-gt-xs-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-gt-xs-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-100,.layout-gt-xs-row>.flex-gt-xs-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-gt-xs-row>.flex-gt-xs-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-gt-xs-row>.flex-gt-xs-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-gt-xs-row>.flex{min-width:0}.layout-gt-xs-column>.flex-gt-xs-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-gt-xs-column>.flex-gt-xs-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-gt-xs-column>.flex{min-height:0}.layout-gt-xs,.layout-gt-xs-column,.layout-gt-xs-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-gt-xs-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}.layout-gt-xs-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}}@media (min-width:600px) and (max-width:959px){.hide-gt-xs:not(.show-gt-xs):not(.show-sm):not(.show),.hide-sm:not(.show-gt-xs):not(.show-sm):not(.show),.hide:not(.show-gt-xs):not(.show-sm):not(.show){display:none}.flex-order-sm--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order-sm--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order-sm--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order-sm--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order-sm--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order-sm--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order-sm--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order-sm--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order-sm--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order-sm--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order-sm--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order-sm--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order-sm--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order-sm--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order-sm--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order-sm--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order-sm--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order-sm--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order-sm--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order-sm--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-sm-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-sm-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-sm-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-sm-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-sm-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-sm-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-sm-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-sm-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-sm-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-sm-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-sm-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-sm-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-sm-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-sm-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-sm-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-sm-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-sm-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-sm-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-sm-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-sm-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-sm-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-sm-0,.offset-sm-0{margin-left:0}[dir=rtl] .flex-offset-sm-0,[dir=rtl] .offset-sm-0{margin-left:auto;margin-right:0}.flex-offset-sm-5,.offset-sm-5{margin-left:5%}[dir=rtl] .flex-offset-sm-5,[dir=rtl] .offset-sm-5{margin-left:auto;margin-right:5%}.flex-offset-sm-10,.offset-sm-10{margin-left:10%}[dir=rtl] .flex-offset-sm-10,[dir=rtl] .offset-sm-10{margin-left:auto;margin-right:10%}.flex-offset-sm-15,.offset-sm-15{margin-left:15%}[dir=rtl] .flex-offset-sm-15,[dir=rtl] .offset-sm-15{margin-left:auto;margin-right:15%}.flex-offset-sm-20,.offset-sm-20{margin-left:20%}[dir=rtl] .flex-offset-sm-20,[dir=rtl] .offset-sm-20{margin-left:auto;margin-right:20%}.flex-offset-sm-25,.offset-sm-25{margin-left:25%}[dir=rtl] .flex-offset-sm-25,[dir=rtl] .offset-sm-25{margin-left:auto;margin-right:25%}.flex-offset-sm-30,.offset-sm-30{margin-left:30%}[dir=rtl] .flex-offset-sm-30,[dir=rtl] .offset-sm-30{margin-left:auto;margin-right:30%}.flex-offset-sm-35,.offset-sm-35{margin-left:35%}[dir=rtl] .flex-offset-sm-35,[dir=rtl] .offset-sm-35{margin-left:auto;margin-right:35%}.flex-offset-sm-40,.offset-sm-40{margin-left:40%}[dir=rtl] .flex-offset-sm-40,[dir=rtl] .offset-sm-40{margin-left:auto;margin-right:40%}.flex-offset-sm-45,.offset-sm-45{margin-left:45%}[dir=rtl] .flex-offset-sm-45,[dir=rtl] .offset-sm-45{margin-left:auto;margin-right:45%}.flex-offset-sm-50,.offset-sm-50{margin-left:50%}[dir=rtl] .flex-offset-sm-50,[dir=rtl] .offset-sm-50{margin-left:auto;margin-right:50%}.flex-offset-sm-55,.offset-sm-55{margin-left:55%}[dir=rtl] .flex-offset-sm-55,[dir=rtl] .offset-sm-55{margin-left:auto;margin-right:55%}.flex-offset-sm-60,.offset-sm-60{margin-left:60%}[dir=rtl] .flex-offset-sm-60,[dir=rtl] .offset-sm-60{margin-left:auto;margin-right:60%}.flex-offset-sm-65,.offset-sm-65{margin-left:65%}[dir=rtl] .flex-offset-sm-65,[dir=rtl] .offset-sm-65{margin-left:auto;margin-right:65%}.flex-offset-sm-70,.offset-sm-70{margin-left:70%}[dir=rtl] .flex-offset-sm-70,[dir=rtl] .offset-sm-70{margin-left:auto;margin-right:70%}.flex-offset-sm-75,.offset-sm-75{margin-left:75%}[dir=rtl] .flex-offset-sm-75,[dir=rtl] .offset-sm-75{margin-left:auto;margin-right:75%}.flex-offset-sm-80,.offset-sm-80{margin-left:80%}[dir=rtl] .flex-offset-sm-80,[dir=rtl] .offset-sm-80{margin-left:auto;margin-right:80%}.flex-offset-sm-85,.offset-sm-85{margin-left:85%}[dir=rtl] .flex-offset-sm-85,[dir=rtl] .offset-sm-85{margin-left:auto;margin-right:85%}.flex-offset-sm-90,.offset-sm-90{margin-left:90%}[dir=rtl] .flex-offset-sm-90,[dir=rtl] .offset-sm-90{margin-left:auto;margin-right:90%}.flex-offset-sm-95,.offset-sm-95{margin-left:95%}[dir=rtl] .flex-offset-sm-95,[dir=rtl] .offset-sm-95{margin-left:auto;margin-right:95%}.flex-offset-sm-33,.offset-sm-33{margin-left:33.33333%}.flex-offset-sm-66,.offset-sm-66{margin-left:66.66667%}[dir=rtl] .flex-offset-sm-66,[dir=rtl] .offset-sm-66{margin-left:auto;margin-right:66.66667%}.layout-align-sm,.layout-align-sm-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align-sm,.layout-align-sm-start,.layout-align-sm-start-center,.layout-align-sm-start-end,.layout-align-sm-start-start,.layout-align-sm-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-sm-center,.layout-align-sm-center-center,.layout-align-sm-center-end,.layout-align-sm-center-start,.layout-align-sm-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-sm-end,.layout-align-sm-end-center,.layout-align-sm-end-end,.layout-align-sm-end-start,.layout-align-sm-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-sm-space-around,.layout-align-sm-space-around-center,.layout-align-sm-space-around-end,.layout-align-sm-space-around-start,.layout-align-sm-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-sm-space-between,.layout-align-sm-space-between-center,.layout-align-sm-space-between-end,.layout-align-sm-space-between-start,.layout-align-sm-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-sm-center-start,.layout-align-sm-end-start,.layout-align-sm-space-around-start,.layout-align-sm-space-between-start,.layout-align-sm-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-sm-center-center,.layout-align-sm-end-center,.layout-align-sm-space-around-center,.layout-align-sm-space-between-center,.layout-align-sm-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-sm-center-center>*,.layout-align-sm-end-center>*,.layout-align-sm-space-around-center>*,.layout-align-sm-space-between-center>*,.layout-align-sm-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-sm-center-end,.layout-align-sm-end-end,.layout-align-sm-space-around-end,.layout-align-sm-space-between-end,.layout-align-sm-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-sm-center-stretch,.layout-align-sm-end-stretch,.layout-align-sm-space-around-stretch,.layout-align-sm-space-between-stretch,.layout-align-sm-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex-sm{-webkit-flex:1;flex:1}.flex-sm,.flex-sm-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-sm-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-sm-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-sm-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-sm-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-sm-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-sm-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-sm-0,.layout-row>.flex-sm-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:0;max-height:100%;box-sizing:border-box}.layout-row>.flex-sm-0{min-width:0}.layout-column>.flex-sm-0{max-width:100%;max-height:0%}.layout-column>.flex-sm-0,.layout-sm-row>.flex-sm-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-row>.flex-sm-0{max-width:0;max-height:100%;min-width:0}.layout-sm-column>.flex-sm-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:0%;box-sizing:border-box;min-height:0}.flex-sm-5,.layout-row>.flex-sm-5{max-width:5%;max-height:100%}.flex-sm-5,.layout-column>.flex-sm-5,.layout-row>.flex-sm-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-5{max-width:100%;max-height:5%}.layout-sm-row>.flex-sm-5{max-width:5%;max-height:100%}.layout-sm-column>.flex-sm-5,.layout-sm-row>.flex-sm-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-5{max-width:100%;max-height:5%}.flex-sm-10,.layout-row>.flex-sm-10{max-width:10%;max-height:100%}.flex-sm-10,.layout-column>.flex-sm-10,.layout-row>.flex-sm-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-10{max-width:100%;max-height:10%}.layout-sm-row>.flex-sm-10{max-width:10%;max-height:100%}.layout-sm-column>.flex-sm-10,.layout-sm-row>.flex-sm-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-10{max-width:100%;max-height:10%}.flex-sm-15,.layout-row>.flex-sm-15{max-width:15%;max-height:100%}.flex-sm-15,.layout-column>.flex-sm-15,.layout-row>.flex-sm-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-15{max-width:100%;max-height:15%}.layout-sm-row>.flex-sm-15{max-width:15%;max-height:100%}.layout-sm-column>.flex-sm-15,.layout-sm-row>.flex-sm-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-15{max-width:100%;max-height:15%}.flex-sm-20,.layout-row>.flex-sm-20{max-width:20%;max-height:100%}.flex-sm-20,.layout-column>.flex-sm-20,.layout-row>.flex-sm-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-20{max-width:100%;max-height:20%}.layout-sm-row>.flex-sm-20{max-width:20%;max-height:100%}.layout-sm-column>.flex-sm-20,.layout-sm-row>.flex-sm-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-20{max-width:100%;max-height:20%}.flex-sm-25,.layout-row>.flex-sm-25{max-width:25%;max-height:100%}.flex-sm-25,.layout-column>.flex-sm-25,.layout-row>.flex-sm-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-25{max-width:100%;max-height:25%}.layout-sm-row>.flex-sm-25{max-width:25%;max-height:100%}.layout-sm-column>.flex-sm-25,.layout-sm-row>.flex-sm-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-25{max-width:100%;max-height:25%}.flex-sm-30,.layout-row>.flex-sm-30{max-width:30%;max-height:100%}.flex-sm-30,.layout-column>.flex-sm-30,.layout-row>.flex-sm-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-30{max-width:100%;max-height:30%}.layout-sm-row>.flex-sm-30{max-width:30%;max-height:100%}.layout-sm-column>.flex-sm-30,.layout-sm-row>.flex-sm-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-30{max-width:100%;max-height:30%}.flex-sm-35,.layout-row>.flex-sm-35{max-width:35%;max-height:100%}.flex-sm-35,.layout-column>.flex-sm-35,.layout-row>.flex-sm-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-35{max-width:100%;max-height:35%}.layout-sm-row>.flex-sm-35{max-width:35%;max-height:100%}.layout-sm-column>.flex-sm-35,.layout-sm-row>.flex-sm-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-35{max-width:100%;max-height:35%}.flex-sm-40,.layout-row>.flex-sm-40{max-width:40%;max-height:100%}.flex-sm-40,.layout-column>.flex-sm-40,.layout-row>.flex-sm-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-40{max-width:100%;max-height:40%}.layout-sm-row>.flex-sm-40{max-width:40%;max-height:100%}.layout-sm-column>.flex-sm-40,.layout-sm-row>.flex-sm-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-40{max-width:100%;max-height:40%}.flex-sm-45,.layout-row>.flex-sm-45{max-width:45%;max-height:100%}.flex-sm-45,.layout-column>.flex-sm-45,.layout-row>.flex-sm-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-45{max-width:100%;max-height:45%}.layout-sm-row>.flex-sm-45{max-width:45%;max-height:100%}.layout-sm-column>.flex-sm-45,.layout-sm-row>.flex-sm-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-45{max-width:100%;max-height:45%}.flex-sm-50,.layout-row>.flex-sm-50{max-width:50%;max-height:100%}.flex-sm-50,.layout-column>.flex-sm-50,.layout-row>.flex-sm-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-50{max-width:100%;max-height:50%}.layout-sm-row>.flex-sm-50{max-width:50%;max-height:100%}.layout-sm-column>.flex-sm-50,.layout-sm-row>.flex-sm-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-50{max-width:100%;max-height:50%}.flex-sm-55,.layout-row>.flex-sm-55{max-width:55%;max-height:100%}.flex-sm-55,.layout-column>.flex-sm-55,.layout-row>.flex-sm-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-55{max-width:100%;max-height:55%}.layout-sm-row>.flex-sm-55{max-width:55%;max-height:100%}.layout-sm-column>.flex-sm-55,.layout-sm-row>.flex-sm-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-55{max-width:100%;max-height:55%}.flex-sm-60,.layout-row>.flex-sm-60{max-width:60%;max-height:100%}.flex-sm-60,.layout-column>.flex-sm-60,.layout-row>.flex-sm-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-60{max-width:100%;max-height:60%}.layout-sm-row>.flex-sm-60{max-width:60%;max-height:100%}.layout-sm-column>.flex-sm-60,.layout-sm-row>.flex-sm-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-60{max-width:100%;max-height:60%}.flex-sm-65,.layout-row>.flex-sm-65{max-width:65%;max-height:100%}.flex-sm-65,.layout-column>.flex-sm-65,.layout-row>.flex-sm-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-65{max-width:100%;max-height:65%}.layout-sm-row>.flex-sm-65{max-width:65%;max-height:100%}.layout-sm-column>.flex-sm-65,.layout-sm-row>.flex-sm-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-65{max-width:100%;max-height:65%}.flex-sm-70,.layout-row>.flex-sm-70{max-width:70%;max-height:100%}.flex-sm-70,.layout-column>.flex-sm-70,.layout-row>.flex-sm-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-70{max-width:100%;max-height:70%}.layout-sm-row>.flex-sm-70{max-width:70%;max-height:100%}.layout-sm-column>.flex-sm-70,.layout-sm-row>.flex-sm-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-70{max-width:100%;max-height:70%}.flex-sm-75,.layout-row>.flex-sm-75{max-width:75%;max-height:100%}.flex-sm-75,.layout-column>.flex-sm-75,.layout-row>.flex-sm-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-75{max-width:100%;max-height:75%}.layout-sm-row>.flex-sm-75{max-width:75%;max-height:100%}.layout-sm-column>.flex-sm-75,.layout-sm-row>.flex-sm-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-75{max-width:100%;max-height:75%}.flex-sm-80,.layout-row>.flex-sm-80{max-width:80%;max-height:100%}.flex-sm-80,.layout-column>.flex-sm-80,.layout-row>.flex-sm-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-80{max-width:100%;max-height:80%}.layout-sm-row>.flex-sm-80{max-width:80%;max-height:100%}.layout-sm-column>.flex-sm-80,.layout-sm-row>.flex-sm-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-80{max-width:100%;max-height:80%}.flex-sm-85,.layout-row>.flex-sm-85{max-width:85%;max-height:100%}.flex-sm-85,.layout-column>.flex-sm-85,.layout-row>.flex-sm-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-85{max-width:100%;max-height:85%}.layout-sm-row>.flex-sm-85{max-width:85%;max-height:100%}.layout-sm-column>.flex-sm-85,.layout-sm-row>.flex-sm-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-85{max-width:100%;max-height:85%}.flex-sm-90,.layout-row>.flex-sm-90{max-width:90%;max-height:100%}.flex-sm-90,.layout-column>.flex-sm-90,.layout-row>.flex-sm-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-90{max-width:100%;max-height:90%}.layout-sm-row>.flex-sm-90{max-width:90%;max-height:100%}.layout-sm-column>.flex-sm-90,.layout-sm-row>.flex-sm-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-sm-column>.flex-sm-90{max-width:100%;max-height:90%}.flex-sm-95,.layout-row>.flex-sm-95{max-width:95%;max-height:100%}.flex-sm-95,.layout-column>.flex-sm-95,.layout-row>.flex-sm-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-sm-95{max-width:100%;max-height:95%}.layout-sm-row>.flex-sm-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-sm-column>.flex-sm-95{max-height:95%}.flex-sm-100,.layout-sm-column>.flex-sm-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-sm-100{max-height:100%}.layout-column>.flex-sm-100,.layout-row>.flex-sm-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-sm-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-sm-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-sm-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-sm-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-sm-column>.flex-sm-100,.layout-sm-row>.flex-sm-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-sm-row>.flex-sm-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-sm-row>.flex-sm-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-sm-row>.flex{min-width:0}.layout-sm-column>.flex-sm-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-sm-column>.flex-sm-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-sm-column>.flex{min-height:0}.layout-sm,.layout-sm-column,.layout-sm-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-sm-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}.layout-sm-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}}@media (min-width:960px){.flex-order-gt-sm--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order-gt-sm--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order-gt-sm--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order-gt-sm--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order-gt-sm--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order-gt-sm--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order-gt-sm--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order-gt-sm--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order-gt-sm--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order-gt-sm--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order-gt-sm--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order-gt-sm--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order-gt-sm--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order-gt-sm--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order-gt-sm--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order-gt-sm--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order-gt-sm--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order-gt-sm--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order-gt-sm--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order-gt-sm--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-gt-sm-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-gt-sm-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-gt-sm-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-gt-sm-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-gt-sm-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-gt-sm-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-gt-sm-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-gt-sm-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-gt-sm-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-gt-sm-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-gt-sm-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-gt-sm-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-gt-sm-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-gt-sm-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-gt-sm-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-gt-sm-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-gt-sm-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-gt-sm-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-gt-sm-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-gt-sm-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-gt-sm-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-gt-sm-0,.offset-gt-sm-0{margin-left:0}[dir=rtl] .flex-offset-gt-sm-0,[dir=rtl] .offset-gt-sm-0{margin-left:auto;margin-right:0}.flex-offset-gt-sm-5,.offset-gt-sm-5{margin-left:5%}[dir=rtl] .flex-offset-gt-sm-5,[dir=rtl] .offset-gt-sm-5{margin-left:auto;margin-right:5%}.flex-offset-gt-sm-10,.offset-gt-sm-10{margin-left:10%}[dir=rtl] .flex-offset-gt-sm-10,[dir=rtl] .offset-gt-sm-10{margin-left:auto;margin-right:10%}.flex-offset-gt-sm-15,.offset-gt-sm-15{margin-left:15%}[dir=rtl] .flex-offset-gt-sm-15,[dir=rtl] .offset-gt-sm-15{margin-left:auto;margin-right:15%}.flex-offset-gt-sm-20,.offset-gt-sm-20{margin-left:20%}[dir=rtl] .flex-offset-gt-sm-20,[dir=rtl] .offset-gt-sm-20{margin-left:auto;margin-right:20%}.flex-offset-gt-sm-25,.offset-gt-sm-25{margin-left:25%}[dir=rtl] .flex-offset-gt-sm-25,[dir=rtl] .offset-gt-sm-25{margin-left:auto;margin-right:25%}.flex-offset-gt-sm-30,.offset-gt-sm-30{margin-left:30%}[dir=rtl] .flex-offset-gt-sm-30,[dir=rtl] .offset-gt-sm-30{margin-left:auto;margin-right:30%}.flex-offset-gt-sm-35,.offset-gt-sm-35{margin-left:35%}[dir=rtl] .flex-offset-gt-sm-35,[dir=rtl] .offset-gt-sm-35{margin-left:auto;margin-right:35%}.flex-offset-gt-sm-40,.offset-gt-sm-40{margin-left:40%}[dir=rtl] .flex-offset-gt-sm-40,[dir=rtl] .offset-gt-sm-40{margin-left:auto;margin-right:40%}.flex-offset-gt-sm-45,.offset-gt-sm-45{margin-left:45%}[dir=rtl] .flex-offset-gt-sm-45,[dir=rtl] .offset-gt-sm-45{margin-left:auto;margin-right:45%}.flex-offset-gt-sm-50,.offset-gt-sm-50{margin-left:50%}[dir=rtl] .flex-offset-gt-sm-50,[dir=rtl] .offset-gt-sm-50{margin-left:auto;margin-right:50%}.flex-offset-gt-sm-55,.offset-gt-sm-55{margin-left:55%}[dir=rtl] .flex-offset-gt-sm-55,[dir=rtl] .offset-gt-sm-55{margin-left:auto;margin-right:55%}.flex-offset-gt-sm-60,.offset-gt-sm-60{margin-left:60%}[dir=rtl] .flex-offset-gt-sm-60,[dir=rtl] .offset-gt-sm-60{margin-left:auto;margin-right:60%}.flex-offset-gt-sm-65,.offset-gt-sm-65{margin-left:65%}[dir=rtl] .flex-offset-gt-sm-65,[dir=rtl] .offset-gt-sm-65{margin-left:auto;margin-right:65%}.flex-offset-gt-sm-70,.offset-gt-sm-70{margin-left:70%}[dir=rtl] .flex-offset-gt-sm-70,[dir=rtl] .offset-gt-sm-70{margin-left:auto;margin-right:70%}.flex-offset-gt-sm-75,.offset-gt-sm-75{margin-left:75%}[dir=rtl] .flex-offset-gt-sm-75,[dir=rtl] .offset-gt-sm-75{margin-left:auto;margin-right:75%}.flex-offset-gt-sm-80,.offset-gt-sm-80{margin-left:80%}[dir=rtl] .flex-offset-gt-sm-80,[dir=rtl] .offset-gt-sm-80{margin-left:auto;margin-right:80%}.flex-offset-gt-sm-85,.offset-gt-sm-85{margin-left:85%}[dir=rtl] .flex-offset-gt-sm-85,[dir=rtl] .offset-gt-sm-85{margin-left:auto;margin-right:85%}.flex-offset-gt-sm-90,.offset-gt-sm-90{margin-left:90%}[dir=rtl] .flex-offset-gt-sm-90,[dir=rtl] .offset-gt-sm-90{margin-left:auto;margin-right:90%}.flex-offset-gt-sm-95,.offset-gt-sm-95{margin-left:95%}[dir=rtl] .flex-offset-gt-sm-95,[dir=rtl] .offset-gt-sm-95{margin-left:auto;margin-right:95%}.flex-offset-gt-sm-33,.offset-gt-sm-33{margin-left:33.33333%}.flex-offset-gt-sm-66,.offset-gt-sm-66{margin-left:66.66667%}[dir=rtl] .flex-offset-gt-sm-66,[dir=rtl] .offset-gt-sm-66{margin-left:auto;margin-right:66.66667%}.layout-align-gt-sm,.layout-align-gt-sm-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align-gt-sm,.layout-align-gt-sm-start,.layout-align-gt-sm-start-center,.layout-align-gt-sm-start-end,.layout-align-gt-sm-start-start,.layout-align-gt-sm-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-gt-sm-center,.layout-align-gt-sm-center-center,.layout-align-gt-sm-center-end,.layout-align-gt-sm-center-start,.layout-align-gt-sm-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-gt-sm-end,.layout-align-gt-sm-end-center,.layout-align-gt-sm-end-end,.layout-align-gt-sm-end-start,.layout-align-gt-sm-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-gt-sm-space-around,.layout-align-gt-sm-space-around-center,.layout-align-gt-sm-space-around-end,.layout-align-gt-sm-space-around-start,.layout-align-gt-sm-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-gt-sm-space-between,.layout-align-gt-sm-space-between-center,.layout-align-gt-sm-space-between-end,.layout-align-gt-sm-space-between-start,.layout-align-gt-sm-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-gt-sm-center-start,.layout-align-gt-sm-end-start,.layout-align-gt-sm-space-around-start,.layout-align-gt-sm-space-between-start,.layout-align-gt-sm-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-gt-sm-center-center,.layout-align-gt-sm-end-center,.layout-align-gt-sm-space-around-center,.layout-align-gt-sm-space-between-center,.layout-align-gt-sm-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-gt-sm-center-center>*,.layout-align-gt-sm-end-center>*,.layout-align-gt-sm-space-around-center>*,.layout-align-gt-sm-space-between-center>*,.layout-align-gt-sm-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-gt-sm-center-end,.layout-align-gt-sm-end-end,.layout-align-gt-sm-space-around-end,.layout-align-gt-sm-space-between-end,.layout-align-gt-sm-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-gt-sm-center-stretch,.layout-align-gt-sm-end-stretch,.layout-align-gt-sm-space-around-stretch,.layout-align-gt-sm-space-between-stretch,.layout-align-gt-sm-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex-gt-sm{-webkit-flex:1;flex:1}.flex-gt-sm,.flex-gt-sm-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-gt-sm-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-gt-sm-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-gt-sm-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-gt-sm-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-gt-sm-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-gt-sm-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-gt-sm-0,.layout-row>.flex-gt-sm-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:0;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-sm-0{min-width:0}.layout-column>.flex-gt-sm-0{max-width:100%;max-height:0%}.layout-column>.flex-gt-sm-0,.layout-gt-sm-row>.flex-gt-sm-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-row>.flex-gt-sm-0{max-width:0;max-height:100%;min-width:0}.layout-gt-sm-column>.flex-gt-sm-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:0%;box-sizing:border-box;min-height:0}.flex-gt-sm-5,.layout-row>.flex-gt-sm-5{max-width:5%;max-height:100%}.flex-gt-sm-5,.layout-column>.flex-gt-sm-5,.layout-row>.flex-gt-sm-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-5{max-width:100%;max-height:5%}.layout-gt-sm-row>.flex-gt-sm-5{max-width:5%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-5,.layout-gt-sm-row>.flex-gt-sm-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-5{max-width:100%;max-height:5%}.flex-gt-sm-10,.layout-row>.flex-gt-sm-10{max-width:10%;max-height:100%}.flex-gt-sm-10,.layout-column>.flex-gt-sm-10,.layout-row>.flex-gt-sm-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-10{max-width:100%;max-height:10%}.layout-gt-sm-row>.flex-gt-sm-10{max-width:10%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-10,.layout-gt-sm-row>.flex-gt-sm-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-10{max-width:100%;max-height:10%}.flex-gt-sm-15,.layout-row>.flex-gt-sm-15{max-width:15%;max-height:100%}.flex-gt-sm-15,.layout-column>.flex-gt-sm-15,.layout-row>.flex-gt-sm-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-15{max-width:100%;max-height:15%}.layout-gt-sm-row>.flex-gt-sm-15{max-width:15%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-15,.layout-gt-sm-row>.flex-gt-sm-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-15{max-width:100%;max-height:15%}.flex-gt-sm-20,.layout-row>.flex-gt-sm-20{max-width:20%;max-height:100%}.flex-gt-sm-20,.layout-column>.flex-gt-sm-20,.layout-row>.flex-gt-sm-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-20{max-width:100%;max-height:20%}.layout-gt-sm-row>.flex-gt-sm-20{max-width:20%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-20,.layout-gt-sm-row>.flex-gt-sm-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-20{max-width:100%;max-height:20%}.flex-gt-sm-25,.layout-row>.flex-gt-sm-25{max-width:25%;max-height:100%}.flex-gt-sm-25,.layout-column>.flex-gt-sm-25,.layout-row>.flex-gt-sm-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-25{max-width:100%;max-height:25%}.layout-gt-sm-row>.flex-gt-sm-25{max-width:25%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-25,.layout-gt-sm-row>.flex-gt-sm-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-25{max-width:100%;max-height:25%}.flex-gt-sm-30,.layout-row>.flex-gt-sm-30{max-width:30%;max-height:100%}.flex-gt-sm-30,.layout-column>.flex-gt-sm-30,.layout-row>.flex-gt-sm-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-30{max-width:100%;max-height:30%}.layout-gt-sm-row>.flex-gt-sm-30{max-width:30%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-30,.layout-gt-sm-row>.flex-gt-sm-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-30{max-width:100%;max-height:30%}.flex-gt-sm-35,.layout-row>.flex-gt-sm-35{max-width:35%;max-height:100%}.flex-gt-sm-35,.layout-column>.flex-gt-sm-35,.layout-row>.flex-gt-sm-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-35{max-width:100%;max-height:35%}.layout-gt-sm-row>.flex-gt-sm-35{max-width:35%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-35,.layout-gt-sm-row>.flex-gt-sm-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-35{max-width:100%;max-height:35%}.flex-gt-sm-40,.layout-row>.flex-gt-sm-40{max-width:40%;max-height:100%}.flex-gt-sm-40,.layout-column>.flex-gt-sm-40,.layout-row>.flex-gt-sm-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-40{max-width:100%;max-height:40%}.layout-gt-sm-row>.flex-gt-sm-40{max-width:40%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-40,.layout-gt-sm-row>.flex-gt-sm-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-40{max-width:100%;max-height:40%}.flex-gt-sm-45,.layout-row>.flex-gt-sm-45{max-width:45%;max-height:100%}.flex-gt-sm-45,.layout-column>.flex-gt-sm-45,.layout-row>.flex-gt-sm-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-45{max-width:100%;max-height:45%}.layout-gt-sm-row>.flex-gt-sm-45{max-width:45%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-45,.layout-gt-sm-row>.flex-gt-sm-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-45{max-width:100%;max-height:45%}.flex-gt-sm-50,.layout-row>.flex-gt-sm-50{max-width:50%;max-height:100%}.flex-gt-sm-50,.layout-column>.flex-gt-sm-50,.layout-row>.flex-gt-sm-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-50{max-width:100%;max-height:50%}.layout-gt-sm-row>.flex-gt-sm-50{max-width:50%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-50,.layout-gt-sm-row>.flex-gt-sm-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-50{max-width:100%;max-height:50%}.flex-gt-sm-55,.layout-row>.flex-gt-sm-55{max-width:55%;max-height:100%}.flex-gt-sm-55,.layout-column>.flex-gt-sm-55,.layout-row>.flex-gt-sm-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-55{max-width:100%;max-height:55%}.layout-gt-sm-row>.flex-gt-sm-55{max-width:55%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-55,.layout-gt-sm-row>.flex-gt-sm-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-55{max-width:100%;max-height:55%}.flex-gt-sm-60,.layout-row>.flex-gt-sm-60{max-width:60%;max-height:100%}.flex-gt-sm-60,.layout-column>.flex-gt-sm-60,.layout-row>.flex-gt-sm-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-60{max-width:100%;max-height:60%}.layout-gt-sm-row>.flex-gt-sm-60{max-width:60%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-60,.layout-gt-sm-row>.flex-gt-sm-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-60{max-width:100%;max-height:60%}.flex-gt-sm-65,.layout-row>.flex-gt-sm-65{max-width:65%;max-height:100%}.flex-gt-sm-65,.layout-column>.flex-gt-sm-65,.layout-row>.flex-gt-sm-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-65{max-width:100%;max-height:65%}.layout-gt-sm-row>.flex-gt-sm-65{max-width:65%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-65,.layout-gt-sm-row>.flex-gt-sm-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-65{max-width:100%;max-height:65%}.flex-gt-sm-70,.layout-row>.flex-gt-sm-70{max-width:70%;max-height:100%}.flex-gt-sm-70,.layout-column>.flex-gt-sm-70,.layout-row>.flex-gt-sm-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-70{max-width:100%;max-height:70%}.layout-gt-sm-row>.flex-gt-sm-70{max-width:70%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-70,.layout-gt-sm-row>.flex-gt-sm-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-70{max-width:100%;max-height:70%}.flex-gt-sm-75,.layout-row>.flex-gt-sm-75{max-width:75%;max-height:100%}.flex-gt-sm-75,.layout-column>.flex-gt-sm-75,.layout-row>.flex-gt-sm-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-75{max-width:100%;max-height:75%}.layout-gt-sm-row>.flex-gt-sm-75{max-width:75%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-75,.layout-gt-sm-row>.flex-gt-sm-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-75{max-width:100%;max-height:75%}.flex-gt-sm-80,.layout-row>.flex-gt-sm-80{max-width:80%;max-height:100%}.flex-gt-sm-80,.layout-column>.flex-gt-sm-80,.layout-row>.flex-gt-sm-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-80{max-width:100%;max-height:80%}.layout-gt-sm-row>.flex-gt-sm-80{max-width:80%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-80,.layout-gt-sm-row>.flex-gt-sm-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-80{max-width:100%;max-height:80%}.flex-gt-sm-85,.layout-row>.flex-gt-sm-85{max-width:85%;max-height:100%}.flex-gt-sm-85,.layout-column>.flex-gt-sm-85,.layout-row>.flex-gt-sm-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-85{max-width:100%;max-height:85%}.layout-gt-sm-row>.flex-gt-sm-85{max-width:85%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-85,.layout-gt-sm-row>.flex-gt-sm-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-85{max-width:100%;max-height:85%}.flex-gt-sm-90,.layout-row>.flex-gt-sm-90{max-width:90%;max-height:100%}.flex-gt-sm-90,.layout-column>.flex-gt-sm-90,.layout-row>.flex-gt-sm-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-90{max-width:100%;max-height:90%}.layout-gt-sm-row>.flex-gt-sm-90{max-width:90%;max-height:100%}.layout-gt-sm-column>.flex-gt-sm-90,.layout-gt-sm-row>.flex-gt-sm-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-90{max-width:100%;max-height:90%}.flex-gt-sm-95,.layout-row>.flex-gt-sm-95{max-width:95%;max-height:100%}.flex-gt-sm-95,.layout-column>.flex-gt-sm-95,.layout-row>.flex-gt-sm-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-sm-95{max-width:100%;max-height:95%}.layout-gt-sm-row>.flex-gt-sm-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-95{max-height:95%}.flex-gt-sm-100,.layout-gt-sm-column>.flex-gt-sm-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-gt-sm-100{max-height:100%}.layout-column>.flex-gt-sm-100,.layout-row>.flex-gt-sm-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-sm-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-sm-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-gt-sm-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-gt-sm-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-100,.layout-gt-sm-row>.flex-gt-sm-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-gt-sm-row>.flex-gt-sm-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-gt-sm-row>.flex-gt-sm-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-gt-sm-row>.flex{min-width:0}.layout-gt-sm-column>.flex-gt-sm-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-gt-sm-column>.flex-gt-sm-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-gt-sm-column>.flex{min-height:0}.layout-gt-sm,.layout-gt-sm-column,.layout-gt-sm-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-gt-sm-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}.layout-gt-sm-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}}@media (min-width:960px) and (max-width:1279px){.hide-gt-sm:not(.show-gt-xs):not(.show-gt-sm):not(.show-md):not(.show),.hide-gt-xs:not(.show-gt-xs):not(.show-gt-sm):not(.show-md):not(.show),.hide-md:not(.show-md):not(.show-gt-sm):not(.show-gt-xs):not(.show),.hide:not(.show-gt-xs):not(.show-gt-sm):not(.show-md):not(.show){display:none}.flex-order-md--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order-md--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order-md--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order-md--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order-md--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order-md--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order-md--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order-md--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order-md--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order-md--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order-md--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order-md--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order-md--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order-md--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order-md--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order-md--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order-md--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order-md--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order-md--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order-md--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-md-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-md-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-md-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-md-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-md-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-md-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-md-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-md-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-md-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-md-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-md-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-md-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-md-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-md-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-md-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-md-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-md-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-md-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-md-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-md-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-md-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-md-0,.offset-md-0{margin-left:0}[dir=rtl] .flex-offset-md-0,[dir=rtl] .offset-md-0{margin-left:auto;margin-right:0}.flex-offset-md-5,.offset-md-5{margin-left:5%}[dir=rtl] .flex-offset-md-5,[dir=rtl] .offset-md-5{margin-left:auto;margin-right:5%}.flex-offset-md-10,.offset-md-10{margin-left:10%}[dir=rtl] .flex-offset-md-10,[dir=rtl] .offset-md-10{margin-left:auto;margin-right:10%}.flex-offset-md-15,.offset-md-15{margin-left:15%}[dir=rtl] .flex-offset-md-15,[dir=rtl] .offset-md-15{margin-left:auto;margin-right:15%}.flex-offset-md-20,.offset-md-20{margin-left:20%}[dir=rtl] .flex-offset-md-20,[dir=rtl] .offset-md-20{margin-left:auto;margin-right:20%}.flex-offset-md-25,.offset-md-25{margin-left:25%}[dir=rtl] .flex-offset-md-25,[dir=rtl] .offset-md-25{margin-left:auto;margin-right:25%}.flex-offset-md-30,.offset-md-30{margin-left:30%}[dir=rtl] .flex-offset-md-30,[dir=rtl] .offset-md-30{margin-left:auto;margin-right:30%}.flex-offset-md-35,.offset-md-35{margin-left:35%}[dir=rtl] .flex-offset-md-35,[dir=rtl] .offset-md-35{margin-left:auto;margin-right:35%}.flex-offset-md-40,.offset-md-40{margin-left:40%}[dir=rtl] .flex-offset-md-40,[dir=rtl] .offset-md-40{margin-left:auto;margin-right:40%}.flex-offset-md-45,.offset-md-45{margin-left:45%}[dir=rtl] .flex-offset-md-45,[dir=rtl] .offset-md-45{margin-left:auto;margin-right:45%}.flex-offset-md-50,.offset-md-50{margin-left:50%}[dir=rtl] .flex-offset-md-50,[dir=rtl] .offset-md-50{margin-left:auto;margin-right:50%}.flex-offset-md-55,.offset-md-55{margin-left:55%}[dir=rtl] .flex-offset-md-55,[dir=rtl] .offset-md-55{margin-left:auto;margin-right:55%}.flex-offset-md-60,.offset-md-60{margin-left:60%}[dir=rtl] .flex-offset-md-60,[dir=rtl] .offset-md-60{margin-left:auto;margin-right:60%}.flex-offset-md-65,.offset-md-65{margin-left:65%}[dir=rtl] .flex-offset-md-65,[dir=rtl] .offset-md-65{margin-left:auto;margin-right:65%}.flex-offset-md-70,.offset-md-70{margin-left:70%}[dir=rtl] .flex-offset-md-70,[dir=rtl] .offset-md-70{margin-left:auto;margin-right:70%}.flex-offset-md-75,.offset-md-75{margin-left:75%}[dir=rtl] .flex-offset-md-75,[dir=rtl] .offset-md-75{margin-left:auto;margin-right:75%}.flex-offset-md-80,.offset-md-80{margin-left:80%}[dir=rtl] .flex-offset-md-80,[dir=rtl] .offset-md-80{margin-left:auto;margin-right:80%}.flex-offset-md-85,.offset-md-85{margin-left:85%}[dir=rtl] .flex-offset-md-85,[dir=rtl] .offset-md-85{margin-left:auto;margin-right:85%}.flex-offset-md-90,.offset-md-90{margin-left:90%}[dir=rtl] .flex-offset-md-90,[dir=rtl] .offset-md-90{margin-left:auto;margin-right:90%}.flex-offset-md-95,.offset-md-95{margin-left:95%}[dir=rtl] .flex-offset-md-95,[dir=rtl] .offset-md-95{margin-left:auto;margin-right:95%}.flex-offset-md-33,.offset-md-33{margin-left:33.33333%}.flex-offset-md-66,.offset-md-66{margin-left:66.66667%}[dir=rtl] .flex-offset-md-66,[dir=rtl] .offset-md-66{margin-left:auto;margin-right:66.66667%}.layout-align-md,.layout-align-md-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align-md,.layout-align-md-start,.layout-align-md-start-center,.layout-align-md-start-end,.layout-align-md-start-start,.layout-align-md-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-md-center,.layout-align-md-center-center,.layout-align-md-center-end,.layout-align-md-center-start,.layout-align-md-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-md-end,.layout-align-md-end-center,.layout-align-md-end-end,.layout-align-md-end-start,.layout-align-md-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-md-space-around,.layout-align-md-space-around-center,.layout-align-md-space-around-end,.layout-align-md-space-around-start,.layout-align-md-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-md-space-between,.layout-align-md-space-between-center,.layout-align-md-space-between-end,.layout-align-md-space-between-start,.layout-align-md-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-md-center-start,.layout-align-md-end-start,.layout-align-md-space-around-start,.layout-align-md-space-between-start,.layout-align-md-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-md-center-center,.layout-align-md-end-center,.layout-align-md-space-around-center,.layout-align-md-space-between-center,.layout-align-md-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-md-center-center>*,.layout-align-md-end-center>*,.layout-align-md-space-around-center>*,.layout-align-md-space-between-center>*,.layout-align-md-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-md-center-end,.layout-align-md-end-end,.layout-align-md-space-around-end,.layout-align-md-space-between-end,.layout-align-md-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-md-center-stretch,.layout-align-md-end-stretch,.layout-align-md-space-around-stretch,.layout-align-md-space-between-stretch,.layout-align-md-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex-md{-webkit-flex:1;flex:1}.flex-md,.flex-md-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-md-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-md-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-md-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-md-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-md-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-md-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-md-0,.layout-row>.flex-md-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:0;max-height:100%;box-sizing:border-box}.layout-row>.flex-md-0{min-width:0}.layout-column>.flex-md-0{max-width:100%;max-height:0%}.layout-column>.flex-md-0,.layout-md-row>.flex-md-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-row>.flex-md-0{max-width:0;max-height:100%;min-width:0}.layout-md-column>.flex-md-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:0%;box-sizing:border-box;min-height:0}.flex-md-5,.layout-row>.flex-md-5{max-width:5%;max-height:100%}.flex-md-5,.layout-column>.flex-md-5,.layout-row>.flex-md-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-5{max-width:100%;max-height:5%}.layout-md-row>.flex-md-5{max-width:5%;max-height:100%}.layout-md-column>.flex-md-5,.layout-md-row>.flex-md-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-5{max-width:100%;max-height:5%}.flex-md-10,.layout-row>.flex-md-10{max-width:10%;max-height:100%}.flex-md-10,.layout-column>.flex-md-10,.layout-row>.flex-md-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-10{max-width:100%;max-height:10%}.layout-md-row>.flex-md-10{max-width:10%;max-height:100%}.layout-md-column>.flex-md-10,.layout-md-row>.flex-md-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-10{max-width:100%;max-height:10%}.flex-md-15,.layout-row>.flex-md-15{max-width:15%;max-height:100%}.flex-md-15,.layout-column>.flex-md-15,.layout-row>.flex-md-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-15{max-width:100%;max-height:15%}.layout-md-row>.flex-md-15{max-width:15%;max-height:100%}.layout-md-column>.flex-md-15,.layout-md-row>.flex-md-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-15{max-width:100%;max-height:15%}.flex-md-20,.layout-row>.flex-md-20{max-width:20%;max-height:100%}.flex-md-20,.layout-column>.flex-md-20,.layout-row>.flex-md-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-20{max-width:100%;max-height:20%}.layout-md-row>.flex-md-20{max-width:20%;max-height:100%}.layout-md-column>.flex-md-20,.layout-md-row>.flex-md-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-20{max-width:100%;max-height:20%}.flex-md-25,.layout-row>.flex-md-25{max-width:25%;max-height:100%}.flex-md-25,.layout-column>.flex-md-25,.layout-row>.flex-md-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-25{max-width:100%;max-height:25%}.layout-md-row>.flex-md-25{max-width:25%;max-height:100%}.layout-md-column>.flex-md-25,.layout-md-row>.flex-md-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-25{max-width:100%;max-height:25%}.flex-md-30,.layout-row>.flex-md-30{max-width:30%;max-height:100%}.flex-md-30,.layout-column>.flex-md-30,.layout-row>.flex-md-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-30{max-width:100%;max-height:30%}.layout-md-row>.flex-md-30{max-width:30%;max-height:100%}.layout-md-column>.flex-md-30,.layout-md-row>.flex-md-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-30{max-width:100%;max-height:30%}.flex-md-35,.layout-row>.flex-md-35{max-width:35%;max-height:100%}.flex-md-35,.layout-column>.flex-md-35,.layout-row>.flex-md-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-35{max-width:100%;max-height:35%}.layout-md-row>.flex-md-35{max-width:35%;max-height:100%}.layout-md-column>.flex-md-35,.layout-md-row>.flex-md-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-35{max-width:100%;max-height:35%}.flex-md-40,.layout-row>.flex-md-40{max-width:40%;max-height:100%}.flex-md-40,.layout-column>.flex-md-40,.layout-row>.flex-md-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-40{max-width:100%;max-height:40%}.layout-md-row>.flex-md-40{max-width:40%;max-height:100%}.layout-md-column>.flex-md-40,.layout-md-row>.flex-md-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-40{max-width:100%;max-height:40%}.flex-md-45,.layout-row>.flex-md-45{max-width:45%;max-height:100%}.flex-md-45,.layout-column>.flex-md-45,.layout-row>.flex-md-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-45{max-width:100%;max-height:45%}.layout-md-row>.flex-md-45{max-width:45%;max-height:100%}.layout-md-column>.flex-md-45,.layout-md-row>.flex-md-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-45{max-width:100%;max-height:45%}.flex-md-50,.layout-row>.flex-md-50{max-width:50%;max-height:100%}.flex-md-50,.layout-column>.flex-md-50,.layout-row>.flex-md-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-50{max-width:100%;max-height:50%}.layout-md-row>.flex-md-50{max-width:50%;max-height:100%}.layout-md-column>.flex-md-50,.layout-md-row>.flex-md-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-50{max-width:100%;max-height:50%}.flex-md-55,.layout-row>.flex-md-55{max-width:55%;max-height:100%}.flex-md-55,.layout-column>.flex-md-55,.layout-row>.flex-md-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-55{max-width:100%;max-height:55%}.layout-md-row>.flex-md-55{max-width:55%;max-height:100%}.layout-md-column>.flex-md-55,.layout-md-row>.flex-md-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-55{max-width:100%;max-height:55%}.flex-md-60,.layout-row>.flex-md-60{max-width:60%;max-height:100%}.flex-md-60,.layout-column>.flex-md-60,.layout-row>.flex-md-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-60{max-width:100%;max-height:60%}.layout-md-row>.flex-md-60{max-width:60%;max-height:100%}.layout-md-column>.flex-md-60,.layout-md-row>.flex-md-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-60{max-width:100%;max-height:60%}.flex-md-65,.layout-row>.flex-md-65{max-width:65%;max-height:100%}.flex-md-65,.layout-column>.flex-md-65,.layout-row>.flex-md-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-65{max-width:100%;max-height:65%}.layout-md-row>.flex-md-65{max-width:65%;max-height:100%}.layout-md-column>.flex-md-65,.layout-md-row>.flex-md-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-65{max-width:100%;max-height:65%}.flex-md-70,.layout-row>.flex-md-70{max-width:70%;max-height:100%}.flex-md-70,.layout-column>.flex-md-70,.layout-row>.flex-md-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-70{max-width:100%;max-height:70%}.layout-md-row>.flex-md-70{max-width:70%;max-height:100%}.layout-md-column>.flex-md-70,.layout-md-row>.flex-md-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-70{max-width:100%;max-height:70%}.flex-md-75,.layout-row>.flex-md-75{max-width:75%;max-height:100%}.flex-md-75,.layout-column>.flex-md-75,.layout-row>.flex-md-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-75{max-width:100%;max-height:75%}.layout-md-row>.flex-md-75{max-width:75%;max-height:100%}.layout-md-column>.flex-md-75,.layout-md-row>.flex-md-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-75{max-width:100%;max-height:75%}.flex-md-80,.layout-row>.flex-md-80{max-width:80%;max-height:100%}.flex-md-80,.layout-column>.flex-md-80,.layout-row>.flex-md-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-80{max-width:100%;max-height:80%}.layout-md-row>.flex-md-80{max-width:80%;max-height:100%}.layout-md-column>.flex-md-80,.layout-md-row>.flex-md-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-80{max-width:100%;max-height:80%}.flex-md-85,.layout-row>.flex-md-85{max-width:85%;max-height:100%}.flex-md-85,.layout-column>.flex-md-85,.layout-row>.flex-md-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-85{max-width:100%;max-height:85%}.layout-md-row>.flex-md-85{max-width:85%;max-height:100%}.layout-md-column>.flex-md-85,.layout-md-row>.flex-md-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-85{max-width:100%;max-height:85%}.flex-md-90,.layout-row>.flex-md-90{max-width:90%;max-height:100%}.flex-md-90,.layout-column>.flex-md-90,.layout-row>.flex-md-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-90{max-width:100%;max-height:90%}.layout-md-row>.flex-md-90{max-width:90%;max-height:100%}.layout-md-column>.flex-md-90,.layout-md-row>.flex-md-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-md-column>.flex-md-90{max-width:100%;max-height:90%}.flex-md-95,.layout-row>.flex-md-95{max-width:95%;max-height:100%}.flex-md-95,.layout-column>.flex-md-95,.layout-row>.flex-md-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-md-95{max-width:100%;max-height:95%}.layout-md-row>.flex-md-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-md-column>.flex-md-95{max-height:95%}.flex-md-100,.layout-md-column>.flex-md-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-md-100{max-height:100%}.layout-column>.flex-md-100,.layout-row>.flex-md-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-md-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-md-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-md-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-md-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-md-column>.flex-md-100,.layout-md-row>.flex-md-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-md-row>.flex-md-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-md-row>.flex-md-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-md-row>.flex{min-width:0}.layout-md-column>.flex-md-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-md-column>.flex-md-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-md-column>.flex{min-height:0}.layout-md,.layout-md-column,.layout-md-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-md-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}.layout-md-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}}@media (min-width:1280px){.flex-order-gt-md--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order-gt-md--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order-gt-md--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order-gt-md--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order-gt-md--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order-gt-md--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order-gt-md--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order-gt-md--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order-gt-md--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order-gt-md--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order-gt-md--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order-gt-md--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order-gt-md--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order-gt-md--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order-gt-md--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order-gt-md--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order-gt-md--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order-gt-md--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order-gt-md--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order-gt-md--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-gt-md-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-gt-md-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-gt-md-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-gt-md-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-gt-md-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-gt-md-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-gt-md-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-gt-md-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-gt-md-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-gt-md-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-gt-md-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-gt-md-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-gt-md-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-gt-md-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-gt-md-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-gt-md-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-gt-md-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-gt-md-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-gt-md-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-gt-md-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-gt-md-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-gt-md-0,.offset-gt-md-0{margin-left:0}[dir=rtl] .flex-offset-gt-md-0,[dir=rtl] .offset-gt-md-0{margin-left:auto;margin-right:0}.flex-offset-gt-md-5,.offset-gt-md-5{margin-left:5%}[dir=rtl] .flex-offset-gt-md-5,[dir=rtl] .offset-gt-md-5{margin-left:auto;margin-right:5%}.flex-offset-gt-md-10,.offset-gt-md-10{margin-left:10%}[dir=rtl] .flex-offset-gt-md-10,[dir=rtl] .offset-gt-md-10{margin-left:auto;margin-right:10%}.flex-offset-gt-md-15,.offset-gt-md-15{margin-left:15%}[dir=rtl] .flex-offset-gt-md-15,[dir=rtl] .offset-gt-md-15{margin-left:auto;margin-right:15%}.flex-offset-gt-md-20,.offset-gt-md-20{margin-left:20%}[dir=rtl] .flex-offset-gt-md-20,[dir=rtl] .offset-gt-md-20{margin-left:auto;margin-right:20%}.flex-offset-gt-md-25,.offset-gt-md-25{margin-left:25%}[dir=rtl] .flex-offset-gt-md-25,[dir=rtl] .offset-gt-md-25{margin-left:auto;margin-right:25%}.flex-offset-gt-md-30,.offset-gt-md-30{margin-left:30%}[dir=rtl] .flex-offset-gt-md-30,[dir=rtl] .offset-gt-md-30{margin-left:auto;margin-right:30%}.flex-offset-gt-md-35,.offset-gt-md-35{margin-left:35%}[dir=rtl] .flex-offset-gt-md-35,[dir=rtl] .offset-gt-md-35{margin-left:auto;margin-right:35%}.flex-offset-gt-md-40,.offset-gt-md-40{margin-left:40%}[dir=rtl] .flex-offset-gt-md-40,[dir=rtl] .offset-gt-md-40{margin-left:auto;margin-right:40%}.flex-offset-gt-md-45,.offset-gt-md-45{margin-left:45%}[dir=rtl] .flex-offset-gt-md-45,[dir=rtl] .offset-gt-md-45{margin-left:auto;margin-right:45%}.flex-offset-gt-md-50,.offset-gt-md-50{margin-left:50%}[dir=rtl] .flex-offset-gt-md-50,[dir=rtl] .offset-gt-md-50{margin-left:auto;margin-right:50%}.flex-offset-gt-md-55,.offset-gt-md-55{margin-left:55%}[dir=rtl] .flex-offset-gt-md-55,[dir=rtl] .offset-gt-md-55{margin-left:auto;margin-right:55%}.flex-offset-gt-md-60,.offset-gt-md-60{margin-left:60%}[dir=rtl] .flex-offset-gt-md-60,[dir=rtl] .offset-gt-md-60{margin-left:auto;margin-right:60%}.flex-offset-gt-md-65,.offset-gt-md-65{margin-left:65%}[dir=rtl] .flex-offset-gt-md-65,[dir=rtl] .offset-gt-md-65{margin-left:auto;margin-right:65%}.flex-offset-gt-md-70,.offset-gt-md-70{margin-left:70%}[dir=rtl] .flex-offset-gt-md-70,[dir=rtl] .offset-gt-md-70{margin-left:auto;margin-right:70%}.flex-offset-gt-md-75,.offset-gt-md-75{margin-left:75%}[dir=rtl] .flex-offset-gt-md-75,[dir=rtl] .offset-gt-md-75{margin-left:auto;margin-right:75%}.flex-offset-gt-md-80,.offset-gt-md-80{margin-left:80%}[dir=rtl] .flex-offset-gt-md-80,[dir=rtl] .offset-gt-md-80{margin-left:auto;margin-right:80%}.flex-offset-gt-md-85,.offset-gt-md-85{margin-left:85%}[dir=rtl] .flex-offset-gt-md-85,[dir=rtl] .offset-gt-md-85{margin-left:auto;margin-right:85%}.flex-offset-gt-md-90,.offset-gt-md-90{margin-left:90%}[dir=rtl] .flex-offset-gt-md-90,[dir=rtl] .offset-gt-md-90{margin-left:auto;margin-right:90%}.flex-offset-gt-md-95,.offset-gt-md-95{margin-left:95%}[dir=rtl] .flex-offset-gt-md-95,[dir=rtl] .offset-gt-md-95{margin-left:auto;margin-right:95%}.flex-offset-gt-md-33,.offset-gt-md-33{margin-left:33.33333%}.flex-offset-gt-md-66,.offset-gt-md-66{margin-left:66.66667%}[dir=rtl] .flex-offset-gt-md-66,[dir=rtl] .offset-gt-md-66{margin-left:auto;margin-right:66.66667%}.layout-align-gt-md,.layout-align-gt-md-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align-gt-md,.layout-align-gt-md-start,.layout-align-gt-md-start-center,.layout-align-gt-md-start-end,.layout-align-gt-md-start-start,.layout-align-gt-md-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-gt-md-center,.layout-align-gt-md-center-center,.layout-align-gt-md-center-end,.layout-align-gt-md-center-start,.layout-align-gt-md-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-gt-md-end,.layout-align-gt-md-end-center,.layout-align-gt-md-end-end,.layout-align-gt-md-end-start,.layout-align-gt-md-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-gt-md-space-around,.layout-align-gt-md-space-around-center,.layout-align-gt-md-space-around-end,.layout-align-gt-md-space-around-start,.layout-align-gt-md-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-gt-md-space-between,.layout-align-gt-md-space-between-center,.layout-align-gt-md-space-between-end,.layout-align-gt-md-space-between-start,.layout-align-gt-md-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-gt-md-center-start,.layout-align-gt-md-end-start,.layout-align-gt-md-space-around-start,.layout-align-gt-md-space-between-start,.layout-align-gt-md-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-gt-md-center-center,.layout-align-gt-md-end-center,.layout-align-gt-md-space-around-center,.layout-align-gt-md-space-between-center,.layout-align-gt-md-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-gt-md-center-center>*,.layout-align-gt-md-end-center>*,.layout-align-gt-md-space-around-center>*,.layout-align-gt-md-space-between-center>*,.layout-align-gt-md-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-gt-md-center-end,.layout-align-gt-md-end-end,.layout-align-gt-md-space-around-end,.layout-align-gt-md-space-between-end,.layout-align-gt-md-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-gt-md-center-stretch,.layout-align-gt-md-end-stretch,.layout-align-gt-md-space-around-stretch,.layout-align-gt-md-space-between-stretch,.layout-align-gt-md-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex-gt-md{-webkit-flex:1;flex:1}.flex-gt-md,.flex-gt-md-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-gt-md-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-gt-md-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-gt-md-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-gt-md-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-gt-md-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-gt-md-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-gt-md-0,.layout-row>.flex-gt-md-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:0;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-md-0{min-width:0}.layout-column>.flex-gt-md-0{max-width:100%;max-height:0%}.layout-column>.flex-gt-md-0,.layout-gt-md-row>.flex-gt-md-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-row>.flex-gt-md-0{max-width:0;max-height:100%;min-width:0}.layout-gt-md-column>.flex-gt-md-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:0%;box-sizing:border-box;min-height:0}.flex-gt-md-5,.layout-row>.flex-gt-md-5{max-width:5%;max-height:100%}.flex-gt-md-5,.layout-column>.flex-gt-md-5,.layout-row>.flex-gt-md-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-5{max-width:100%;max-height:5%}.layout-gt-md-row>.flex-gt-md-5{max-width:5%;max-height:100%}.layout-gt-md-column>.flex-gt-md-5,.layout-gt-md-row>.flex-gt-md-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-5{max-width:100%;max-height:5%}.flex-gt-md-10,.layout-row>.flex-gt-md-10{max-width:10%;max-height:100%}.flex-gt-md-10,.layout-column>.flex-gt-md-10,.layout-row>.flex-gt-md-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-10{max-width:100%;max-height:10%}.layout-gt-md-row>.flex-gt-md-10{max-width:10%;max-height:100%}.layout-gt-md-column>.flex-gt-md-10,.layout-gt-md-row>.flex-gt-md-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-10{max-width:100%;max-height:10%}.flex-gt-md-15,.layout-row>.flex-gt-md-15{max-width:15%;max-height:100%}.flex-gt-md-15,.layout-column>.flex-gt-md-15,.layout-row>.flex-gt-md-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-15{max-width:100%;max-height:15%}.layout-gt-md-row>.flex-gt-md-15{max-width:15%;max-height:100%}.layout-gt-md-column>.flex-gt-md-15,.layout-gt-md-row>.flex-gt-md-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-15{max-width:100%;max-height:15%}.flex-gt-md-20,.layout-row>.flex-gt-md-20{max-width:20%;max-height:100%}.flex-gt-md-20,.layout-column>.flex-gt-md-20,.layout-row>.flex-gt-md-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-20{max-width:100%;max-height:20%}.layout-gt-md-row>.flex-gt-md-20{max-width:20%;max-height:100%}.layout-gt-md-column>.flex-gt-md-20,.layout-gt-md-row>.flex-gt-md-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-20{max-width:100%;max-height:20%}.flex-gt-md-25,.layout-row>.flex-gt-md-25{max-width:25%;max-height:100%}.flex-gt-md-25,.layout-column>.flex-gt-md-25,.layout-row>.flex-gt-md-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-25{max-width:100%;max-height:25%}.layout-gt-md-row>.flex-gt-md-25{max-width:25%;max-height:100%}.layout-gt-md-column>.flex-gt-md-25,.layout-gt-md-row>.flex-gt-md-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-25{max-width:100%;max-height:25%}.flex-gt-md-30,.layout-row>.flex-gt-md-30{max-width:30%;max-height:100%}.flex-gt-md-30,.layout-column>.flex-gt-md-30,.layout-row>.flex-gt-md-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-30{max-width:100%;max-height:30%}.layout-gt-md-row>.flex-gt-md-30{max-width:30%;max-height:100%}.layout-gt-md-column>.flex-gt-md-30,.layout-gt-md-row>.flex-gt-md-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-30{max-width:100%;max-height:30%}.flex-gt-md-35,.layout-row>.flex-gt-md-35{max-width:35%;max-height:100%}.flex-gt-md-35,.layout-column>.flex-gt-md-35,.layout-row>.flex-gt-md-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-35{max-width:100%;max-height:35%}.layout-gt-md-row>.flex-gt-md-35{max-width:35%;max-height:100%}.layout-gt-md-column>.flex-gt-md-35,.layout-gt-md-row>.flex-gt-md-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-35{max-width:100%;max-height:35%}.flex-gt-md-40,.layout-row>.flex-gt-md-40{max-width:40%;max-height:100%}.flex-gt-md-40,.layout-column>.flex-gt-md-40,.layout-row>.flex-gt-md-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-40{max-width:100%;max-height:40%}.layout-gt-md-row>.flex-gt-md-40{max-width:40%;max-height:100%}.layout-gt-md-column>.flex-gt-md-40,.layout-gt-md-row>.flex-gt-md-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-40{max-width:100%;max-height:40%}.flex-gt-md-45,.layout-row>.flex-gt-md-45{max-width:45%;max-height:100%}.flex-gt-md-45,.layout-column>.flex-gt-md-45,.layout-row>.flex-gt-md-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-45{max-width:100%;max-height:45%}.layout-gt-md-row>.flex-gt-md-45{max-width:45%;max-height:100%}.layout-gt-md-column>.flex-gt-md-45,.layout-gt-md-row>.flex-gt-md-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-45{max-width:100%;max-height:45%}.flex-gt-md-50,.layout-row>.flex-gt-md-50{max-width:50%;max-height:100%}.flex-gt-md-50,.layout-column>.flex-gt-md-50,.layout-row>.flex-gt-md-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-50{max-width:100%;max-height:50%}.layout-gt-md-row>.flex-gt-md-50{max-width:50%;max-height:100%}.layout-gt-md-column>.flex-gt-md-50,.layout-gt-md-row>.flex-gt-md-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-50{max-width:100%;max-height:50%}.flex-gt-md-55,.layout-row>.flex-gt-md-55{max-width:55%;max-height:100%}.flex-gt-md-55,.layout-column>.flex-gt-md-55,.layout-row>.flex-gt-md-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-55{max-width:100%;max-height:55%}.layout-gt-md-row>.flex-gt-md-55{max-width:55%;max-height:100%}.layout-gt-md-column>.flex-gt-md-55,.layout-gt-md-row>.flex-gt-md-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-55{max-width:100%;max-height:55%}.flex-gt-md-60,.layout-row>.flex-gt-md-60{max-width:60%;max-height:100%}.flex-gt-md-60,.layout-column>.flex-gt-md-60,.layout-row>.flex-gt-md-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-60{max-width:100%;max-height:60%}.layout-gt-md-row>.flex-gt-md-60{max-width:60%;max-height:100%}.layout-gt-md-column>.flex-gt-md-60,.layout-gt-md-row>.flex-gt-md-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-60{max-width:100%;max-height:60%}.flex-gt-md-65,.layout-row>.flex-gt-md-65{max-width:65%;max-height:100%}.flex-gt-md-65,.layout-column>.flex-gt-md-65,.layout-row>.flex-gt-md-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-65{max-width:100%;max-height:65%}.layout-gt-md-row>.flex-gt-md-65{max-width:65%;max-height:100%}.layout-gt-md-column>.flex-gt-md-65,.layout-gt-md-row>.flex-gt-md-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-65{max-width:100%;max-height:65%}.flex-gt-md-70,.layout-row>.flex-gt-md-70{max-width:70%;max-height:100%}.flex-gt-md-70,.layout-column>.flex-gt-md-70,.layout-row>.flex-gt-md-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-70{max-width:100%;max-height:70%}.layout-gt-md-row>.flex-gt-md-70{max-width:70%;max-height:100%}.layout-gt-md-column>.flex-gt-md-70,.layout-gt-md-row>.flex-gt-md-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-70{max-width:100%;max-height:70%}.flex-gt-md-75,.layout-row>.flex-gt-md-75{max-width:75%;max-height:100%}.flex-gt-md-75,.layout-column>.flex-gt-md-75,.layout-row>.flex-gt-md-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-75{max-width:100%;max-height:75%}.layout-gt-md-row>.flex-gt-md-75{max-width:75%;max-height:100%}.layout-gt-md-column>.flex-gt-md-75,.layout-gt-md-row>.flex-gt-md-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-75{max-width:100%;max-height:75%}.flex-gt-md-80,.layout-row>.flex-gt-md-80{max-width:80%;max-height:100%}.flex-gt-md-80,.layout-column>.flex-gt-md-80,.layout-row>.flex-gt-md-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-80{max-width:100%;max-height:80%}.layout-gt-md-row>.flex-gt-md-80{max-width:80%;max-height:100%}.layout-gt-md-column>.flex-gt-md-80,.layout-gt-md-row>.flex-gt-md-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-80{max-width:100%;max-height:80%}.flex-gt-md-85,.layout-row>.flex-gt-md-85{max-width:85%;max-height:100%}.flex-gt-md-85,.layout-column>.flex-gt-md-85,.layout-row>.flex-gt-md-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-85{max-width:100%;max-height:85%}.layout-gt-md-row>.flex-gt-md-85{max-width:85%;max-height:100%}.layout-gt-md-column>.flex-gt-md-85,.layout-gt-md-row>.flex-gt-md-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-85{max-width:100%;max-height:85%}.flex-gt-md-90,.layout-row>.flex-gt-md-90{max-width:90%;max-height:100%}.flex-gt-md-90,.layout-column>.flex-gt-md-90,.layout-row>.flex-gt-md-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-90{max-width:100%;max-height:90%}.layout-gt-md-row>.flex-gt-md-90{max-width:90%;max-height:100%}.layout-gt-md-column>.flex-gt-md-90,.layout-gt-md-row>.flex-gt-md-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-90{max-width:100%;max-height:90%}.flex-gt-md-95,.layout-row>.flex-gt-md-95{max-width:95%;max-height:100%}.flex-gt-md-95,.layout-column>.flex-gt-md-95,.layout-row>.flex-gt-md-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-md-95{max-width:100%;max-height:95%}.layout-gt-md-row>.flex-gt-md-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-95{max-height:95%}.flex-gt-md-100,.layout-gt-md-column>.flex-gt-md-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-gt-md-100{max-height:100%}.layout-column>.flex-gt-md-100,.layout-row>.flex-gt-md-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-md-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-md-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-gt-md-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-gt-md-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-100,.layout-gt-md-row>.flex-gt-md-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-gt-md-row>.flex-gt-md-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-gt-md-row>.flex-gt-md-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-gt-md-row>.flex{min-width:0}.layout-gt-md-column>.flex-gt-md-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-gt-md-column>.flex-gt-md-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-gt-md-column>.flex{min-height:0}.layout-gt-md,.layout-gt-md-column,.layout-gt-md-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-gt-md-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}.layout-gt-md-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}}@media (min-width:1280px) and (max-width:1919px){.hide-gt-md:not(.show-gt-xs):not(.show-gt-sm):not(.show-gt-md):not(.show-lg):not(.show),.hide-gt-sm:not(.show-gt-xs):not(.show-gt-sm):not(.show-gt-md):not(.show-lg):not(.show),.hide-gt-xs:not(.show-gt-xs):not(.show-gt-sm):not(.show-gt-md):not(.show-lg):not(.show),.hide-lg:not(.show-lg):not(.show-gt-md):not(.show-gt-sm):not(.show-gt-xs):not(.show),.hide:not(.show-gt-xs):not(.show-gt-sm):not(.show-gt-md):not(.show-lg):not(.show){display:none}.flex-order-lg--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order-lg--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order-lg--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order-lg--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order-lg--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order-lg--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order-lg--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order-lg--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order-lg--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order-lg--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order-lg--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order-lg--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order-lg--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order-lg--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order-lg--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order-lg--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order-lg--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order-lg--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order-lg--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order-lg--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-lg-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-lg-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-lg-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-lg-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-lg-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-lg-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-lg-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-lg-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-lg-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-lg-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-lg-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-lg-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-lg-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-lg-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-lg-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-lg-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-lg-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-lg-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-lg-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-lg-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-lg-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-lg-0,.offset-lg-0{margin-left:0}[dir=rtl] .flex-offset-lg-0,[dir=rtl] .offset-lg-0{margin-left:auto;margin-right:0}.flex-offset-lg-5,.offset-lg-5{margin-left:5%}[dir=rtl] .flex-offset-lg-5,[dir=rtl] .offset-lg-5{margin-left:auto;margin-right:5%}.flex-offset-lg-10,.offset-lg-10{margin-left:10%}[dir=rtl] .flex-offset-lg-10,[dir=rtl] .offset-lg-10{margin-left:auto;margin-right:10%}.flex-offset-lg-15,.offset-lg-15{margin-left:15%}[dir=rtl] .flex-offset-lg-15,[dir=rtl] .offset-lg-15{margin-left:auto;margin-right:15%}.flex-offset-lg-20,.offset-lg-20{margin-left:20%}[dir=rtl] .flex-offset-lg-20,[dir=rtl] .offset-lg-20{margin-left:auto;margin-right:20%}.flex-offset-lg-25,.offset-lg-25{margin-left:25%}[dir=rtl] .flex-offset-lg-25,[dir=rtl] .offset-lg-25{margin-left:auto;margin-right:25%}.flex-offset-lg-30,.offset-lg-30{margin-left:30%}[dir=rtl] .flex-offset-lg-30,[dir=rtl] .offset-lg-30{margin-left:auto;margin-right:30%}.flex-offset-lg-35,.offset-lg-35{margin-left:35%}[dir=rtl] .flex-offset-lg-35,[dir=rtl] .offset-lg-35{margin-left:auto;margin-right:35%}.flex-offset-lg-40,.offset-lg-40{margin-left:40%}[dir=rtl] .flex-offset-lg-40,[dir=rtl] .offset-lg-40{margin-left:auto;margin-right:40%}.flex-offset-lg-45,.offset-lg-45{margin-left:45%}[dir=rtl] .flex-offset-lg-45,[dir=rtl] .offset-lg-45{margin-left:auto;margin-right:45%}.flex-offset-lg-50,.offset-lg-50{margin-left:50%}[dir=rtl] .flex-offset-lg-50,[dir=rtl] .offset-lg-50{margin-left:auto;margin-right:50%}.flex-offset-lg-55,.offset-lg-55{margin-left:55%}[dir=rtl] .flex-offset-lg-55,[dir=rtl] .offset-lg-55{margin-left:auto;margin-right:55%}.flex-offset-lg-60,.offset-lg-60{margin-left:60%}[dir=rtl] .flex-offset-lg-60,[dir=rtl] .offset-lg-60{margin-left:auto;margin-right:60%}.flex-offset-lg-65,.offset-lg-65{margin-left:65%}[dir=rtl] .flex-offset-lg-65,[dir=rtl] .offset-lg-65{margin-left:auto;margin-right:65%}.flex-offset-lg-70,.offset-lg-70{margin-left:70%}[dir=rtl] .flex-offset-lg-70,[dir=rtl] .offset-lg-70{margin-left:auto;margin-right:70%}.flex-offset-lg-75,.offset-lg-75{margin-left:75%}[dir=rtl] .flex-offset-lg-75,[dir=rtl] .offset-lg-75{margin-left:auto;margin-right:75%}.flex-offset-lg-80,.offset-lg-80{margin-left:80%}[dir=rtl] .flex-offset-lg-80,[dir=rtl] .offset-lg-80{margin-left:auto;margin-right:80%}.flex-offset-lg-85,.offset-lg-85{margin-left:85%}[dir=rtl] .flex-offset-lg-85,[dir=rtl] .offset-lg-85{margin-left:auto;margin-right:85%}.flex-offset-lg-90,.offset-lg-90{margin-left:90%}[dir=rtl] .flex-offset-lg-90,[dir=rtl] .offset-lg-90{margin-left:auto;margin-right:90%}.flex-offset-lg-95,.offset-lg-95{margin-left:95%}[dir=rtl] .flex-offset-lg-95,[dir=rtl] .offset-lg-95{margin-left:auto;margin-right:95%}.flex-offset-lg-33,.offset-lg-33{margin-left:33.33333%}.flex-offset-lg-66,.offset-lg-66{margin-left:66.66667%}[dir=rtl] .flex-offset-lg-66,[dir=rtl] .offset-lg-66{margin-left:auto;margin-right:66.66667%}.layout-align-lg,.layout-align-lg-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align-lg,.layout-align-lg-start,.layout-align-lg-start-center,.layout-align-lg-start-end,.layout-align-lg-start-start,.layout-align-lg-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-lg-center,.layout-align-lg-center-center,.layout-align-lg-center-end,.layout-align-lg-center-start,.layout-align-lg-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-lg-end,.layout-align-lg-end-center,.layout-align-lg-end-end,.layout-align-lg-end-start,.layout-align-lg-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-lg-space-around,.layout-align-lg-space-around-center,.layout-align-lg-space-around-end,.layout-align-lg-space-around-start,.layout-align-lg-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-lg-space-between,.layout-align-lg-space-between-center,.layout-align-lg-space-between-end,.layout-align-lg-space-between-start,.layout-align-lg-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-lg-center-start,.layout-align-lg-end-start,.layout-align-lg-space-around-start,.layout-align-lg-space-between-start,.layout-align-lg-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-lg-center-center,.layout-align-lg-end-center,.layout-align-lg-space-around-center,.layout-align-lg-space-between-center,.layout-align-lg-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-lg-center-center>*,.layout-align-lg-end-center>*,.layout-align-lg-space-around-center>*,.layout-align-lg-space-between-center>*,.layout-align-lg-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-lg-center-end,.layout-align-lg-end-end,.layout-align-lg-space-around-end,.layout-align-lg-space-between-end,.layout-align-lg-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-lg-center-stretch,.layout-align-lg-end-stretch,.layout-align-lg-space-around-stretch,.layout-align-lg-space-between-stretch,.layout-align-lg-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex-lg{-webkit-flex:1;flex:1}.flex-lg,.flex-lg-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-lg-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-lg-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-lg-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-lg-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-lg-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-lg-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-lg-0,.layout-row>.flex-lg-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:0;max-height:100%;box-sizing:border-box}.layout-row>.flex-lg-0{min-width:0}.layout-column>.flex-lg-0{max-width:100%;max-height:0%}.layout-column>.flex-lg-0,.layout-lg-row>.flex-lg-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-row>.flex-lg-0{max-width:0;max-height:100%;min-width:0}.layout-lg-column>.flex-lg-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:0%;box-sizing:border-box;min-height:0}.flex-lg-5,.layout-row>.flex-lg-5{max-width:5%;max-height:100%}.flex-lg-5,.layout-column>.flex-lg-5,.layout-row>.flex-lg-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-5{max-width:100%;max-height:5%}.layout-lg-row>.flex-lg-5{max-width:5%;max-height:100%}.layout-lg-column>.flex-lg-5,.layout-lg-row>.flex-lg-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-5{max-width:100%;max-height:5%}.flex-lg-10,.layout-row>.flex-lg-10{max-width:10%;max-height:100%}.flex-lg-10,.layout-column>.flex-lg-10,.layout-row>.flex-lg-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-10{max-width:100%;max-height:10%}.layout-lg-row>.flex-lg-10{max-width:10%;max-height:100%}.layout-lg-column>.flex-lg-10,.layout-lg-row>.flex-lg-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-10{max-width:100%;max-height:10%}.flex-lg-15,.layout-row>.flex-lg-15{max-width:15%;max-height:100%}.flex-lg-15,.layout-column>.flex-lg-15,.layout-row>.flex-lg-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-15{max-width:100%;max-height:15%}.layout-lg-row>.flex-lg-15{max-width:15%;max-height:100%}.layout-lg-column>.flex-lg-15,.layout-lg-row>.flex-lg-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-15{max-width:100%;max-height:15%}.flex-lg-20,.layout-row>.flex-lg-20{max-width:20%;max-height:100%}.flex-lg-20,.layout-column>.flex-lg-20,.layout-row>.flex-lg-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-20{max-width:100%;max-height:20%}.layout-lg-row>.flex-lg-20{max-width:20%;max-height:100%}.layout-lg-column>.flex-lg-20,.layout-lg-row>.flex-lg-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-20{max-width:100%;max-height:20%}.flex-lg-25,.layout-row>.flex-lg-25{max-width:25%;max-height:100%}.flex-lg-25,.layout-column>.flex-lg-25,.layout-row>.flex-lg-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-25{max-width:100%;max-height:25%}.layout-lg-row>.flex-lg-25{max-width:25%;max-height:100%}.layout-lg-column>.flex-lg-25,.layout-lg-row>.flex-lg-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-25{max-width:100%;max-height:25%}.flex-lg-30,.layout-row>.flex-lg-30{max-width:30%;max-height:100%}.flex-lg-30,.layout-column>.flex-lg-30,.layout-row>.flex-lg-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-30{max-width:100%;max-height:30%}.layout-lg-row>.flex-lg-30{max-width:30%;max-height:100%}.layout-lg-column>.flex-lg-30,.layout-lg-row>.flex-lg-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-30{max-width:100%;max-height:30%}.flex-lg-35,.layout-row>.flex-lg-35{max-width:35%;max-height:100%}.flex-lg-35,.layout-column>.flex-lg-35,.layout-row>.flex-lg-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-35{max-width:100%;max-height:35%}.layout-lg-row>.flex-lg-35{max-width:35%;max-height:100%}.layout-lg-column>.flex-lg-35,.layout-lg-row>.flex-lg-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-35{max-width:100%;max-height:35%}.flex-lg-40,.layout-row>.flex-lg-40{max-width:40%;max-height:100%}.flex-lg-40,.layout-column>.flex-lg-40,.layout-row>.flex-lg-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-40{max-width:100%;max-height:40%}.layout-lg-row>.flex-lg-40{max-width:40%;max-height:100%}.layout-lg-column>.flex-lg-40,.layout-lg-row>.flex-lg-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-40{max-width:100%;max-height:40%}.flex-lg-45,.layout-row>.flex-lg-45{max-width:45%;max-height:100%}.flex-lg-45,.layout-column>.flex-lg-45,.layout-row>.flex-lg-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-45{max-width:100%;max-height:45%}.layout-lg-row>.flex-lg-45{max-width:45%;max-height:100%}.layout-lg-column>.flex-lg-45,.layout-lg-row>.flex-lg-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-45{max-width:100%;max-height:45%}.flex-lg-50,.layout-row>.flex-lg-50{max-width:50%;max-height:100%}.flex-lg-50,.layout-column>.flex-lg-50,.layout-row>.flex-lg-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-50{max-width:100%;max-height:50%}.layout-lg-row>.flex-lg-50{max-width:50%;max-height:100%}.layout-lg-column>.flex-lg-50,.layout-lg-row>.flex-lg-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-50{max-width:100%;max-height:50%}.flex-lg-55,.layout-row>.flex-lg-55{max-width:55%;max-height:100%}.flex-lg-55,.layout-column>.flex-lg-55,.layout-row>.flex-lg-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-55{max-width:100%;max-height:55%}.layout-lg-row>.flex-lg-55{max-width:55%;max-height:100%}.layout-lg-column>.flex-lg-55,.layout-lg-row>.flex-lg-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-55{max-width:100%;max-height:55%}.flex-lg-60,.layout-row>.flex-lg-60{max-width:60%;max-height:100%}.flex-lg-60,.layout-column>.flex-lg-60,.layout-row>.flex-lg-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-60{max-width:100%;max-height:60%}.layout-lg-row>.flex-lg-60{max-width:60%;max-height:100%}.layout-lg-column>.flex-lg-60,.layout-lg-row>.flex-lg-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-60{max-width:100%;max-height:60%}.flex-lg-65,.layout-row>.flex-lg-65{max-width:65%;max-height:100%}.flex-lg-65,.layout-column>.flex-lg-65,.layout-row>.flex-lg-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-65{max-width:100%;max-height:65%}.layout-lg-row>.flex-lg-65{max-width:65%;max-height:100%}.layout-lg-column>.flex-lg-65,.layout-lg-row>.flex-lg-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-65{max-width:100%;max-height:65%}.flex-lg-70,.layout-row>.flex-lg-70{max-width:70%;max-height:100%}.flex-lg-70,.layout-column>.flex-lg-70,.layout-row>.flex-lg-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-70{max-width:100%;max-height:70%}.layout-lg-row>.flex-lg-70{max-width:70%;max-height:100%}.layout-lg-column>.flex-lg-70,.layout-lg-row>.flex-lg-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-70{max-width:100%;max-height:70%}.flex-lg-75,.layout-row>.flex-lg-75{max-width:75%;max-height:100%}.flex-lg-75,.layout-column>.flex-lg-75,.layout-row>.flex-lg-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-75{max-width:100%;max-height:75%}.layout-lg-row>.flex-lg-75{max-width:75%;max-height:100%}.layout-lg-column>.flex-lg-75,.layout-lg-row>.flex-lg-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-75{max-width:100%;max-height:75%}.flex-lg-80,.layout-row>.flex-lg-80{max-width:80%;max-height:100%}.flex-lg-80,.layout-column>.flex-lg-80,.layout-row>.flex-lg-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-80{max-width:100%;max-height:80%}.layout-lg-row>.flex-lg-80{max-width:80%;max-height:100%}.layout-lg-column>.flex-lg-80,.layout-lg-row>.flex-lg-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-80{max-width:100%;max-height:80%}.flex-lg-85,.layout-row>.flex-lg-85{max-width:85%;max-height:100%}.flex-lg-85,.layout-column>.flex-lg-85,.layout-row>.flex-lg-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-85{max-width:100%;max-height:85%}.layout-lg-row>.flex-lg-85{max-width:85%;max-height:100%}.layout-lg-column>.flex-lg-85,.layout-lg-row>.flex-lg-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-85{max-width:100%;max-height:85%}.flex-lg-90,.layout-row>.flex-lg-90{max-width:90%;max-height:100%}.flex-lg-90,.layout-column>.flex-lg-90,.layout-row>.flex-lg-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-90{max-width:100%;max-height:90%}.layout-lg-row>.flex-lg-90{max-width:90%;max-height:100%}.layout-lg-column>.flex-lg-90,.layout-lg-row>.flex-lg-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-lg-column>.flex-lg-90{max-width:100%;max-height:90%}.flex-lg-95,.layout-row>.flex-lg-95{max-width:95%;max-height:100%}.flex-lg-95,.layout-column>.flex-lg-95,.layout-row>.flex-lg-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-lg-95{max-width:100%;max-height:95%}.layout-lg-row>.flex-lg-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-lg-column>.flex-lg-95{max-height:95%}.flex-lg-100,.layout-lg-column>.flex-lg-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-lg-100{max-height:100%}.layout-column>.flex-lg-100,.layout-row>.flex-lg-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-lg-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-lg-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-lg-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-lg-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-lg-column>.flex-lg-100,.layout-lg-row>.flex-lg-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-lg-row>.flex-lg-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-lg-row>.flex-lg-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-lg-row>.flex{min-width:0}.layout-lg-column>.flex-lg-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-lg-column>.flex-lg-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-lg-column>.flex{min-height:0}.layout-lg,.layout-lg-column,.layout-lg-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-lg-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}.layout-lg-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}}@media (min-width:1920px){.flex-order-gt-lg--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order-gt-lg--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order-gt-lg--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order-gt-lg--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order-gt-lg--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order-gt-lg--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order-gt-lg--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order-gt-lg--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order-gt-lg--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order-gt-lg--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order-gt-lg--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order-gt-lg--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order-gt-lg--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order-gt-lg--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order-gt-lg--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order-gt-lg--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order-gt-lg--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order-gt-lg--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order-gt-lg--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order-gt-lg--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-gt-lg-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-gt-lg-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-gt-lg-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-gt-lg-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-gt-lg-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-gt-lg-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-gt-lg-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-gt-lg-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-gt-lg-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-gt-lg-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-gt-lg-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-gt-lg-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-gt-lg-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-gt-lg-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-gt-lg-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-gt-lg-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-gt-lg-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-gt-lg-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-gt-lg-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-gt-lg-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-gt-lg-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-gt-lg-0,.offset-gt-lg-0{margin-left:0}[dir=rtl] .flex-offset-gt-lg-0,[dir=rtl] .offset-gt-lg-0{margin-left:auto;margin-right:0}.flex-offset-gt-lg-5,.offset-gt-lg-5{margin-left:5%}[dir=rtl] .flex-offset-gt-lg-5,[dir=rtl] .offset-gt-lg-5{margin-left:auto;margin-right:5%}.flex-offset-gt-lg-10,.offset-gt-lg-10{margin-left:10%}[dir=rtl] .flex-offset-gt-lg-10,[dir=rtl] .offset-gt-lg-10{margin-left:auto;margin-right:10%}.flex-offset-gt-lg-15,.offset-gt-lg-15{margin-left:15%}[dir=rtl] .flex-offset-gt-lg-15,[dir=rtl] .offset-gt-lg-15{margin-left:auto;margin-right:15%}.flex-offset-gt-lg-20,.offset-gt-lg-20{margin-left:20%}[dir=rtl] .flex-offset-gt-lg-20,[dir=rtl] .offset-gt-lg-20{margin-left:auto;margin-right:20%}.flex-offset-gt-lg-25,.offset-gt-lg-25{margin-left:25%}[dir=rtl] .flex-offset-gt-lg-25,[dir=rtl] .offset-gt-lg-25{margin-left:auto;margin-right:25%}.flex-offset-gt-lg-30,.offset-gt-lg-30{margin-left:30%}[dir=rtl] .flex-offset-gt-lg-30,[dir=rtl] .offset-gt-lg-30{margin-left:auto;margin-right:30%}.flex-offset-gt-lg-35,.offset-gt-lg-35{margin-left:35%}[dir=rtl] .flex-offset-gt-lg-35,[dir=rtl] .offset-gt-lg-35{margin-left:auto;margin-right:35%}.flex-offset-gt-lg-40,.offset-gt-lg-40{margin-left:40%}[dir=rtl] .flex-offset-gt-lg-40,[dir=rtl] .offset-gt-lg-40{margin-left:auto;margin-right:40%}.flex-offset-gt-lg-45,.offset-gt-lg-45{margin-left:45%}[dir=rtl] .flex-offset-gt-lg-45,[dir=rtl] .offset-gt-lg-45{margin-left:auto;margin-right:45%}.flex-offset-gt-lg-50,.offset-gt-lg-50{margin-left:50%}[dir=rtl] .flex-offset-gt-lg-50,[dir=rtl] .offset-gt-lg-50{margin-left:auto;margin-right:50%}.flex-offset-gt-lg-55,.offset-gt-lg-55{margin-left:55%}[dir=rtl] .flex-offset-gt-lg-55,[dir=rtl] .offset-gt-lg-55{margin-left:auto;margin-right:55%}.flex-offset-gt-lg-60,.offset-gt-lg-60{margin-left:60%}[dir=rtl] .flex-offset-gt-lg-60,[dir=rtl] .offset-gt-lg-60{margin-left:auto;margin-right:60%}.flex-offset-gt-lg-65,.offset-gt-lg-65{margin-left:65%}[dir=rtl] .flex-offset-gt-lg-65,[dir=rtl] .offset-gt-lg-65{margin-left:auto;margin-right:65%}.flex-offset-gt-lg-70,.offset-gt-lg-70{margin-left:70%}[dir=rtl] .flex-offset-gt-lg-70,[dir=rtl] .offset-gt-lg-70{margin-left:auto;margin-right:70%}.flex-offset-gt-lg-75,.offset-gt-lg-75{margin-left:75%}[dir=rtl] .flex-offset-gt-lg-75,[dir=rtl] .offset-gt-lg-75{margin-left:auto;margin-right:75%}.flex-offset-gt-lg-80,.offset-gt-lg-80{margin-left:80%}[dir=rtl] .flex-offset-gt-lg-80,[dir=rtl] .offset-gt-lg-80{margin-left:auto;margin-right:80%}.flex-offset-gt-lg-85,.offset-gt-lg-85{margin-left:85%}[dir=rtl] .flex-offset-gt-lg-85,[dir=rtl] .offset-gt-lg-85{margin-left:auto;margin-right:85%}.flex-offset-gt-lg-90,.offset-gt-lg-90{margin-left:90%}[dir=rtl] .flex-offset-gt-lg-90,[dir=rtl] .offset-gt-lg-90{margin-left:auto;margin-right:90%}.flex-offset-gt-lg-95,.offset-gt-lg-95{margin-left:95%}[dir=rtl] .flex-offset-gt-lg-95,[dir=rtl] .offset-gt-lg-95{margin-left:auto;margin-right:95%}.flex-offset-gt-lg-33,.offset-gt-lg-33{margin-left:33.33333%}.flex-offset-gt-lg-66,.offset-gt-lg-66{margin-left:66.66667%}[dir=rtl] .flex-offset-gt-lg-66,[dir=rtl] .offset-gt-lg-66{margin-left:auto;margin-right:66.66667%}.layout-align-gt-lg,.layout-align-gt-lg-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align-gt-lg,.layout-align-gt-lg-start,.layout-align-gt-lg-start-center,.layout-align-gt-lg-start-end,.layout-align-gt-lg-start-start,.layout-align-gt-lg-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-gt-lg-center,.layout-align-gt-lg-center-center,.layout-align-gt-lg-center-end,.layout-align-gt-lg-center-start,.layout-align-gt-lg-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-gt-lg-end,.layout-align-gt-lg-end-center,.layout-align-gt-lg-end-end,.layout-align-gt-lg-end-start,.layout-align-gt-lg-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-gt-lg-space-around,.layout-align-gt-lg-space-around-center,.layout-align-gt-lg-space-around-end,.layout-align-gt-lg-space-around-start,.layout-align-gt-lg-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-gt-lg-space-between,.layout-align-gt-lg-space-between-center,.layout-align-gt-lg-space-between-end,.layout-align-gt-lg-space-between-start,.layout-align-gt-lg-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-gt-lg-center-start,.layout-align-gt-lg-end-start,.layout-align-gt-lg-space-around-start,.layout-align-gt-lg-space-between-start,.layout-align-gt-lg-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-gt-lg-center-center,.layout-align-gt-lg-end-center,.layout-align-gt-lg-space-around-center,.layout-align-gt-lg-space-between-center,.layout-align-gt-lg-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-gt-lg-center-center>*,.layout-align-gt-lg-end-center>*,.layout-align-gt-lg-space-around-center>*,.layout-align-gt-lg-space-between-center>*,.layout-align-gt-lg-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-gt-lg-center-end,.layout-align-gt-lg-end-end,.layout-align-gt-lg-space-around-end,.layout-align-gt-lg-space-between-end,.layout-align-gt-lg-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-gt-lg-center-stretch,.layout-align-gt-lg-end-stretch,.layout-align-gt-lg-space-around-stretch,.layout-align-gt-lg-space-between-stretch,.layout-align-gt-lg-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex-gt-lg{-webkit-flex:1;flex:1}.flex-gt-lg,.flex-gt-lg-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-gt-lg-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-gt-lg-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-gt-lg-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-gt-lg-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-gt-lg-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-gt-lg-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-gt-lg-0,.layout-row>.flex-gt-lg-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:0;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-lg-0{min-width:0}.layout-column>.flex-gt-lg-0{max-width:100%;max-height:0%}.layout-column>.flex-gt-lg-0,.layout-gt-lg-row>.flex-gt-lg-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-row>.flex-gt-lg-0{max-width:0;max-height:100%;min-width:0}.layout-gt-lg-column>.flex-gt-lg-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:0%;box-sizing:border-box;min-height:0}.flex-gt-lg-5,.layout-row>.flex-gt-lg-5{max-width:5%;max-height:100%}.flex-gt-lg-5,.layout-column>.flex-gt-lg-5,.layout-row>.flex-gt-lg-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-5{max-width:100%;max-height:5%}.layout-gt-lg-row>.flex-gt-lg-5{max-width:5%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-5,.layout-gt-lg-row>.flex-gt-lg-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-5{max-width:100%;max-height:5%}.flex-gt-lg-10,.layout-row>.flex-gt-lg-10{max-width:10%;max-height:100%}.flex-gt-lg-10,.layout-column>.flex-gt-lg-10,.layout-row>.flex-gt-lg-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-10{max-width:100%;max-height:10%}.layout-gt-lg-row>.flex-gt-lg-10{max-width:10%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-10,.layout-gt-lg-row>.flex-gt-lg-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-10{max-width:100%;max-height:10%}.flex-gt-lg-15,.layout-row>.flex-gt-lg-15{max-width:15%;max-height:100%}.flex-gt-lg-15,.layout-column>.flex-gt-lg-15,.layout-row>.flex-gt-lg-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-15{max-width:100%;max-height:15%}.layout-gt-lg-row>.flex-gt-lg-15{max-width:15%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-15,.layout-gt-lg-row>.flex-gt-lg-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-15{max-width:100%;max-height:15%}.flex-gt-lg-20,.layout-row>.flex-gt-lg-20{max-width:20%;max-height:100%}.flex-gt-lg-20,.layout-column>.flex-gt-lg-20,.layout-row>.flex-gt-lg-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-20{max-width:100%;max-height:20%}.layout-gt-lg-row>.flex-gt-lg-20{max-width:20%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-20,.layout-gt-lg-row>.flex-gt-lg-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-20{max-width:100%;max-height:20%}.flex-gt-lg-25,.layout-row>.flex-gt-lg-25{max-width:25%;max-height:100%}.flex-gt-lg-25,.layout-column>.flex-gt-lg-25,.layout-row>.flex-gt-lg-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-25{max-width:100%;max-height:25%}.layout-gt-lg-row>.flex-gt-lg-25{max-width:25%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-25,.layout-gt-lg-row>.flex-gt-lg-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-25{max-width:100%;max-height:25%}.flex-gt-lg-30,.layout-row>.flex-gt-lg-30{max-width:30%;max-height:100%}.flex-gt-lg-30,.layout-column>.flex-gt-lg-30,.layout-row>.flex-gt-lg-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-30{max-width:100%;max-height:30%}.layout-gt-lg-row>.flex-gt-lg-30{max-width:30%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-30,.layout-gt-lg-row>.flex-gt-lg-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-30{max-width:100%;max-height:30%}.flex-gt-lg-35,.layout-row>.flex-gt-lg-35{max-width:35%;max-height:100%}.flex-gt-lg-35,.layout-column>.flex-gt-lg-35,.layout-row>.flex-gt-lg-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-35{max-width:100%;max-height:35%}.layout-gt-lg-row>.flex-gt-lg-35{max-width:35%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-35,.layout-gt-lg-row>.flex-gt-lg-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-35{max-width:100%;max-height:35%}.flex-gt-lg-40,.layout-row>.flex-gt-lg-40{max-width:40%;max-height:100%}.flex-gt-lg-40,.layout-column>.flex-gt-lg-40,.layout-row>.flex-gt-lg-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-40{max-width:100%;max-height:40%}.layout-gt-lg-row>.flex-gt-lg-40{max-width:40%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-40,.layout-gt-lg-row>.flex-gt-lg-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-40{max-width:100%;max-height:40%}.flex-gt-lg-45,.layout-row>.flex-gt-lg-45{max-width:45%;max-height:100%}.flex-gt-lg-45,.layout-column>.flex-gt-lg-45,.layout-row>.flex-gt-lg-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-45{max-width:100%;max-height:45%}.layout-gt-lg-row>.flex-gt-lg-45{max-width:45%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-45,.layout-gt-lg-row>.flex-gt-lg-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-45{max-width:100%;max-height:45%}.flex-gt-lg-50,.layout-row>.flex-gt-lg-50{max-width:50%;max-height:100%}.flex-gt-lg-50,.layout-column>.flex-gt-lg-50,.layout-row>.flex-gt-lg-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-50{max-width:100%;max-height:50%}.layout-gt-lg-row>.flex-gt-lg-50{max-width:50%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-50,.layout-gt-lg-row>.flex-gt-lg-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-50{max-width:100%;max-height:50%}.flex-gt-lg-55,.layout-row>.flex-gt-lg-55{max-width:55%;max-height:100%}.flex-gt-lg-55,.layout-column>.flex-gt-lg-55,.layout-row>.flex-gt-lg-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-55{max-width:100%;max-height:55%}.layout-gt-lg-row>.flex-gt-lg-55{max-width:55%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-55,.layout-gt-lg-row>.flex-gt-lg-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-55{max-width:100%;max-height:55%}.flex-gt-lg-60,.layout-row>.flex-gt-lg-60{max-width:60%;max-height:100%}.flex-gt-lg-60,.layout-column>.flex-gt-lg-60,.layout-row>.flex-gt-lg-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-60{max-width:100%;max-height:60%}.layout-gt-lg-row>.flex-gt-lg-60{max-width:60%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-60,.layout-gt-lg-row>.flex-gt-lg-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-60{max-width:100%;max-height:60%}.flex-gt-lg-65,.layout-row>.flex-gt-lg-65{max-width:65%;max-height:100%}.flex-gt-lg-65,.layout-column>.flex-gt-lg-65,.layout-row>.flex-gt-lg-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-65{max-width:100%;max-height:65%}.layout-gt-lg-row>.flex-gt-lg-65{max-width:65%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-65,.layout-gt-lg-row>.flex-gt-lg-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-65{max-width:100%;max-height:65%}.flex-gt-lg-70,.layout-row>.flex-gt-lg-70{max-width:70%;max-height:100%}.flex-gt-lg-70,.layout-column>.flex-gt-lg-70,.layout-row>.flex-gt-lg-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-70{max-width:100%;max-height:70%}.layout-gt-lg-row>.flex-gt-lg-70{max-width:70%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-70,.layout-gt-lg-row>.flex-gt-lg-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-70{max-width:100%;max-height:70%}.flex-gt-lg-75,.layout-row>.flex-gt-lg-75{max-width:75%;max-height:100%}.flex-gt-lg-75,.layout-column>.flex-gt-lg-75,.layout-row>.flex-gt-lg-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-75{max-width:100%;max-height:75%}.layout-gt-lg-row>.flex-gt-lg-75{max-width:75%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-75,.layout-gt-lg-row>.flex-gt-lg-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-75{max-width:100%;max-height:75%}.flex-gt-lg-80,.layout-row>.flex-gt-lg-80{max-width:80%;max-height:100%}.flex-gt-lg-80,.layout-column>.flex-gt-lg-80,.layout-row>.flex-gt-lg-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-80{max-width:100%;max-height:80%}.layout-gt-lg-row>.flex-gt-lg-80{max-width:80%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-80,.layout-gt-lg-row>.flex-gt-lg-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-80{max-width:100%;max-height:80%}.flex-gt-lg-85,.layout-row>.flex-gt-lg-85{max-width:85%;max-height:100%}.flex-gt-lg-85,.layout-column>.flex-gt-lg-85,.layout-row>.flex-gt-lg-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-85{max-width:100%;max-height:85%}.layout-gt-lg-row>.flex-gt-lg-85{max-width:85%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-85,.layout-gt-lg-row>.flex-gt-lg-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-85{max-width:100%;max-height:85%}.flex-gt-lg-90,.layout-row>.flex-gt-lg-90{max-width:90%;max-height:100%}.flex-gt-lg-90,.layout-column>.flex-gt-lg-90,.layout-row>.flex-gt-lg-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-90{max-width:100%;max-height:90%}.layout-gt-lg-row>.flex-gt-lg-90{max-width:90%;max-height:100%}.layout-gt-lg-column>.flex-gt-lg-90,.layout-gt-lg-row>.flex-gt-lg-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-90{max-width:100%;max-height:90%}.flex-gt-lg-95,.layout-row>.flex-gt-lg-95{max-width:95%;max-height:100%}.flex-gt-lg-95,.layout-column>.flex-gt-lg-95,.layout-row>.flex-gt-lg-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-gt-lg-95{max-width:100%;max-height:95%}.layout-gt-lg-row>.flex-gt-lg-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-95{max-height:95%}.flex-gt-lg-100,.layout-gt-lg-column>.flex-gt-lg-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-gt-lg-100{max-height:100%}.layout-column>.flex-gt-lg-100,.layout-row>.flex-gt-lg-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-lg-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-gt-lg-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-gt-lg-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-gt-lg-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-100,.layout-gt-lg-row>.flex-gt-lg-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-gt-lg-row>.flex-gt-lg-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-gt-lg-row>.flex-gt-lg-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-gt-lg-row>.flex{min-width:0}.layout-gt-lg-column>.flex-gt-lg-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-gt-lg-column>.flex-gt-lg-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-gt-lg-column>.flex{min-height:0}.layout-gt-lg,.layout-gt-lg-column,.layout-gt-lg-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-gt-lg-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}.layout-gt-lg-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}.flex-order-xl--20{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}.flex-order-xl--19{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}.flex-order-xl--18{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}.flex-order-xl--17{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}.flex-order-xl--16{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}.flex-order-xl--15{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}.flex-order-xl--14{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}.flex-order-xl--13{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}.flex-order-xl--12{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}.flex-order-xl--11{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}.flex-order-xl--10{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}.flex-order-xl--9{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}.flex-order-xl--8{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}.flex-order-xl--7{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}.flex-order-xl--6{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}.flex-order-xl--5{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}.flex-order-xl--4{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}.flex-order-xl--3{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}.flex-order-xl--2{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}.flex-order-xl--1{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}.flex-order-xl-0{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}.flex-order-xl-1{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}.flex-order-xl-2{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}.flex-order-xl-3{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}.flex-order-xl-4{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}.flex-order-xl-5{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}.flex-order-xl-6{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}.flex-order-xl-7{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}.flex-order-xl-8{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}.flex-order-xl-9{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}.flex-order-xl-10{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}.flex-order-xl-11{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}.flex-order-xl-12{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}.flex-order-xl-13{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}.flex-order-xl-14{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}.flex-order-xl-15{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}.flex-order-xl-16{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}.flex-order-xl-17{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}.flex-order-xl-18{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}.flex-order-xl-19{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}.flex-order-xl-20{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}.flex-offset-xl-0,.offset-xl-0{margin-left:0}[dir=rtl] .flex-offset-xl-0,[dir=rtl] .offset-xl-0{margin-left:auto;margin-right:0}.flex-offset-xl-5,.offset-xl-5{margin-left:5%}[dir=rtl] .flex-offset-xl-5,[dir=rtl] .offset-xl-5{margin-left:auto;margin-right:5%}.flex-offset-xl-10,.offset-xl-10{margin-left:10%}[dir=rtl] .flex-offset-xl-10,[dir=rtl] .offset-xl-10{margin-left:auto;margin-right:10%}.flex-offset-xl-15,.offset-xl-15{margin-left:15%}[dir=rtl] .flex-offset-xl-15,[dir=rtl] .offset-xl-15{margin-left:auto;margin-right:15%}.flex-offset-xl-20,.offset-xl-20{margin-left:20%}[dir=rtl] .flex-offset-xl-20,[dir=rtl] .offset-xl-20{margin-left:auto;margin-right:20%}.flex-offset-xl-25,.offset-xl-25{margin-left:25%}[dir=rtl] .flex-offset-xl-25,[dir=rtl] .offset-xl-25{margin-left:auto;margin-right:25%}.flex-offset-xl-30,.offset-xl-30{margin-left:30%}[dir=rtl] .flex-offset-xl-30,[dir=rtl] .offset-xl-30{margin-left:auto;margin-right:30%}.flex-offset-xl-35,.offset-xl-35{margin-left:35%}[dir=rtl] .flex-offset-xl-35,[dir=rtl] .offset-xl-35{margin-left:auto;margin-right:35%}.flex-offset-xl-40,.offset-xl-40{margin-left:40%}[dir=rtl] .flex-offset-xl-40,[dir=rtl] .offset-xl-40{margin-left:auto;margin-right:40%}.flex-offset-xl-45,.offset-xl-45{margin-left:45%}[dir=rtl] .flex-offset-xl-45,[dir=rtl] .offset-xl-45{margin-left:auto;margin-right:45%}.flex-offset-xl-50,.offset-xl-50{margin-left:50%}[dir=rtl] .flex-offset-xl-50,[dir=rtl] .offset-xl-50{margin-left:auto;margin-right:50%}.flex-offset-xl-55,.offset-xl-55{margin-left:55%}[dir=rtl] .flex-offset-xl-55,[dir=rtl] .offset-xl-55{margin-left:auto;margin-right:55%}.flex-offset-xl-60,.offset-xl-60{margin-left:60%}[dir=rtl] .flex-offset-xl-60,[dir=rtl] .offset-xl-60{margin-left:auto;margin-right:60%}.flex-offset-xl-65,.offset-xl-65{margin-left:65%}[dir=rtl] .flex-offset-xl-65,[dir=rtl] .offset-xl-65{margin-left:auto;margin-right:65%}.flex-offset-xl-70,.offset-xl-70{margin-left:70%}[dir=rtl] .flex-offset-xl-70,[dir=rtl] .offset-xl-70{margin-left:auto;margin-right:70%}.flex-offset-xl-75,.offset-xl-75{margin-left:75%}[dir=rtl] .flex-offset-xl-75,[dir=rtl] .offset-xl-75{margin-left:auto;margin-right:75%}.flex-offset-xl-80,.offset-xl-80{margin-left:80%}[dir=rtl] .flex-offset-xl-80,[dir=rtl] .offset-xl-80{margin-left:auto;margin-right:80%}.flex-offset-xl-85,.offset-xl-85{margin-left:85%}[dir=rtl] .flex-offset-xl-85,[dir=rtl] .offset-xl-85{margin-left:auto;margin-right:85%}.flex-offset-xl-90,.offset-xl-90{margin-left:90%}[dir=rtl] .flex-offset-xl-90,[dir=rtl] .offset-xl-90{margin-left:auto;margin-right:90%}.flex-offset-xl-95,.offset-xl-95{margin-left:95%}[dir=rtl] .flex-offset-xl-95,[dir=rtl] .offset-xl-95{margin-left:auto;margin-right:95%}.flex-offset-xl-33,.offset-xl-33{margin-left:33.33333%}.flex-offset-xl-66,.offset-xl-66{margin-left:66.66667%}[dir=rtl] .flex-offset-xl-66,[dir=rtl] .offset-xl-66{margin-left:auto;margin-right:66.66667%}.layout-align-xl,.layout-align-xl-start-stretch{-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}.layout-align-xl,.layout-align-xl-start,.layout-align-xl-start-center,.layout-align-xl-start-end,.layout-align-xl-start-start,.layout-align-xl-start-stretch{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}.layout-align-xl-center,.layout-align-xl-center-center,.layout-align-xl-center-end,.layout-align-xl-center-start,.layout-align-xl-center-stretch{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}.layout-align-xl-end,.layout-align-xl-end-center,.layout-align-xl-end-end,.layout-align-xl-end-start,.layout-align-xl-end-stretch{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}.layout-align-xl-space-around,.layout-align-xl-space-around-center,.layout-align-xl-space-around-end,.layout-align-xl-space-around-start,.layout-align-xl-space-around-stretch{-webkit-justify-content:space-around;justify-content:space-around}.layout-align-xl-space-between,.layout-align-xl-space-between-center,.layout-align-xl-space-between-end,.layout-align-xl-space-between-start,.layout-align-xl-space-between-stretch{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between}.layout-align-xl-center-start,.layout-align-xl-end-start,.layout-align-xl-space-around-start,.layout-align-xl-space-between-start,.layout-align-xl-start-start{-webkit-box-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.layout-align-xl-center-center,.layout-align-xl-end-center,.layout-align-xl-space-around-center,.layout-align-xl-space-between-center,.layout-align-xl-start-center{-webkit-box-align:center;-webkit-align-items:center;align-items:center;-webkit-align-content:center;align-content:center;max-width:100%}.layout-align-xl-center-center>*,.layout-align-xl-end-center>*,.layout-align-xl-space-around-center>*,.layout-align-xl-space-between-center>*,.layout-align-xl-start-center>*{max-width:100%;box-sizing:border-box}.layout-align-xl-center-end,.layout-align-xl-end-end,.layout-align-xl-space-around-end,.layout-align-xl-space-between-end,.layout-align-xl-start-end{-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;-webkit-align-content:flex-end;align-content:flex-end}.layout-align-xl-center-stretch,.layout-align-xl-end-stretch,.layout-align-xl-space-around-stretch,.layout-align-xl-space-between-stretch,.layout-align-xl-start-stretch{-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;align-content:stretch}.flex-xl{-webkit-flex:1;flex:1}.flex-xl,.flex-xl-grow{-webkit-box-flex:1;box-sizing:border-box}.flex-xl-grow{-webkit-flex:1 1 100%;flex:1 1 100%}.flex-xl-initial{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-xl-auto{-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;box-sizing:border-box}.flex-xl-none{-webkit-box-flex:0;-webkit-flex:0 0 auto;flex:0 0 auto;box-sizing:border-box}.flex-xl-noshrink{-webkit-box-flex:1;-webkit-flex:1 0 auto;flex:1 0 auto;box-sizing:border-box}.flex-xl-nogrow{-webkit-box-flex:0;-webkit-flex:0 1 auto;flex:0 1 auto;box-sizing:border-box}.flex-xl-0,.layout-row>.flex-xl-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:0;max-height:100%;box-sizing:border-box}.layout-row>.flex-xl-0{min-width:0}.layout-column>.flex-xl-0{max-width:100%;max-height:0%}.layout-column>.flex-xl-0,.layout-xl-row>.flex-xl-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-row>.flex-xl-0{max-width:0;max-height:100%;min-width:0}.layout-xl-column>.flex-xl-0{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:0%;box-sizing:border-box;min-height:0}.flex-xl-5,.layout-row>.flex-xl-5{max-width:5%;max-height:100%}.flex-xl-5,.layout-column>.flex-xl-5,.layout-row>.flex-xl-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-5{max-width:100%;max-height:5%}.layout-xl-row>.flex-xl-5{max-width:5%;max-height:100%}.layout-xl-column>.flex-xl-5,.layout-xl-row>.flex-xl-5{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-5{max-width:100%;max-height:5%}.flex-xl-10,.layout-row>.flex-xl-10{max-width:10%;max-height:100%}.flex-xl-10,.layout-column>.flex-xl-10,.layout-row>.flex-xl-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-10{max-width:100%;max-height:10%}.layout-xl-row>.flex-xl-10{max-width:10%;max-height:100%}.layout-xl-column>.flex-xl-10,.layout-xl-row>.flex-xl-10{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-10{max-width:100%;max-height:10%}.flex-xl-15,.layout-row>.flex-xl-15{max-width:15%;max-height:100%}.flex-xl-15,.layout-column>.flex-xl-15,.layout-row>.flex-xl-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-15{max-width:100%;max-height:15%}.layout-xl-row>.flex-xl-15{max-width:15%;max-height:100%}.layout-xl-column>.flex-xl-15,.layout-xl-row>.flex-xl-15{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-15{max-width:100%;max-height:15%}.flex-xl-20,.layout-row>.flex-xl-20{max-width:20%;max-height:100%}.flex-xl-20,.layout-column>.flex-xl-20,.layout-row>.flex-xl-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-20{max-width:100%;max-height:20%}.layout-xl-row>.flex-xl-20{max-width:20%;max-height:100%}.layout-xl-column>.flex-xl-20,.layout-xl-row>.flex-xl-20{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-20{max-width:100%;max-height:20%}.flex-xl-25,.layout-row>.flex-xl-25{max-width:25%;max-height:100%}.flex-xl-25,.layout-column>.flex-xl-25,.layout-row>.flex-xl-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-25{max-width:100%;max-height:25%}.layout-xl-row>.flex-xl-25{max-width:25%;max-height:100%}.layout-xl-column>.flex-xl-25,.layout-xl-row>.flex-xl-25{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-25{max-width:100%;max-height:25%}.flex-xl-30,.layout-row>.flex-xl-30{max-width:30%;max-height:100%}.flex-xl-30,.layout-column>.flex-xl-30,.layout-row>.flex-xl-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-30{max-width:100%;max-height:30%}.layout-xl-row>.flex-xl-30{max-width:30%;max-height:100%}.layout-xl-column>.flex-xl-30,.layout-xl-row>.flex-xl-30{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-30{max-width:100%;max-height:30%}.flex-xl-35,.layout-row>.flex-xl-35{max-width:35%;max-height:100%}.flex-xl-35,.layout-column>.flex-xl-35,.layout-row>.flex-xl-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-35{max-width:100%;max-height:35%}.layout-xl-row>.flex-xl-35{max-width:35%;max-height:100%}.layout-xl-column>.flex-xl-35,.layout-xl-row>.flex-xl-35{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-35{max-width:100%;max-height:35%}.flex-xl-40,.layout-row>.flex-xl-40{max-width:40%;max-height:100%}.flex-xl-40,.layout-column>.flex-xl-40,.layout-row>.flex-xl-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-40{max-width:100%;max-height:40%}.layout-xl-row>.flex-xl-40{max-width:40%;max-height:100%}.layout-xl-column>.flex-xl-40,.layout-xl-row>.flex-xl-40{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-40{max-width:100%;max-height:40%}.flex-xl-45,.layout-row>.flex-xl-45{max-width:45%;max-height:100%}.flex-xl-45,.layout-column>.flex-xl-45,.layout-row>.flex-xl-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-45{max-width:100%;max-height:45%}.layout-xl-row>.flex-xl-45{max-width:45%;max-height:100%}.layout-xl-column>.flex-xl-45,.layout-xl-row>.flex-xl-45{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-45{max-width:100%;max-height:45%}.flex-xl-50,.layout-row>.flex-xl-50{max-width:50%;max-height:100%}.flex-xl-50,.layout-column>.flex-xl-50,.layout-row>.flex-xl-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-50{max-width:100%;max-height:50%}.layout-xl-row>.flex-xl-50{max-width:50%;max-height:100%}.layout-xl-column>.flex-xl-50,.layout-xl-row>.flex-xl-50{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-50{max-width:100%;max-height:50%}.flex-xl-55,.layout-row>.flex-xl-55{max-width:55%;max-height:100%}.flex-xl-55,.layout-column>.flex-xl-55,.layout-row>.flex-xl-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-55{max-width:100%;max-height:55%}.layout-xl-row>.flex-xl-55{max-width:55%;max-height:100%}.layout-xl-column>.flex-xl-55,.layout-xl-row>.flex-xl-55{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-55{max-width:100%;max-height:55%}.flex-xl-60,.layout-row>.flex-xl-60{max-width:60%;max-height:100%}.flex-xl-60,.layout-column>.flex-xl-60,.layout-row>.flex-xl-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-60{max-width:100%;max-height:60%}.layout-xl-row>.flex-xl-60{max-width:60%;max-height:100%}.layout-xl-column>.flex-xl-60,.layout-xl-row>.flex-xl-60{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-60{max-width:100%;max-height:60%}.flex-xl-65,.layout-row>.flex-xl-65{max-width:65%;max-height:100%}.flex-xl-65,.layout-column>.flex-xl-65,.layout-row>.flex-xl-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-65{max-width:100%;max-height:65%}.layout-xl-row>.flex-xl-65{max-width:65%;max-height:100%}.layout-xl-column>.flex-xl-65,.layout-xl-row>.flex-xl-65{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-65{max-width:100%;max-height:65%}.flex-xl-70,.layout-row>.flex-xl-70{max-width:70%;max-height:100%}.flex-xl-70,.layout-column>.flex-xl-70,.layout-row>.flex-xl-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-70{max-width:100%;max-height:70%}.layout-xl-row>.flex-xl-70{max-width:70%;max-height:100%}.layout-xl-column>.flex-xl-70,.layout-xl-row>.flex-xl-70{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-70{max-width:100%;max-height:70%}.flex-xl-75,.layout-row>.flex-xl-75{max-width:75%;max-height:100%}.flex-xl-75,.layout-column>.flex-xl-75,.layout-row>.flex-xl-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-75{max-width:100%;max-height:75%}.layout-xl-row>.flex-xl-75{max-width:75%;max-height:100%}.layout-xl-column>.flex-xl-75,.layout-xl-row>.flex-xl-75{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-75{max-width:100%;max-height:75%}.flex-xl-80,.layout-row>.flex-xl-80{max-width:80%;max-height:100%}.flex-xl-80,.layout-column>.flex-xl-80,.layout-row>.flex-xl-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-80{max-width:100%;max-height:80%}.layout-xl-row>.flex-xl-80{max-width:80%;max-height:100%}.layout-xl-column>.flex-xl-80,.layout-xl-row>.flex-xl-80{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-80{max-width:100%;max-height:80%}.flex-xl-85,.layout-row>.flex-xl-85{max-width:85%;max-height:100%}.flex-xl-85,.layout-column>.flex-xl-85,.layout-row>.flex-xl-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-85{max-width:100%;max-height:85%}.layout-xl-row>.flex-xl-85{max-width:85%;max-height:100%}.layout-xl-column>.flex-xl-85,.layout-xl-row>.flex-xl-85{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-85{max-width:100%;max-height:85%}.flex-xl-90,.layout-row>.flex-xl-90{max-width:90%;max-height:100%}.flex-xl-90,.layout-column>.flex-xl-90,.layout-row>.flex-xl-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-90{max-width:100%;max-height:90%}.layout-xl-row>.flex-xl-90{max-width:90%;max-height:100%}.layout-xl-column>.flex-xl-90,.layout-xl-row>.flex-xl-90{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-xl-column>.flex-xl-90{max-width:100%;max-height:90%}.flex-xl-95,.layout-row>.flex-xl-95{max-width:95%;max-height:100%}.flex-xl-95,.layout-column>.flex-xl-95,.layout-row>.flex-xl-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;box-sizing:border-box}.layout-column>.flex-xl-95{max-width:100%;max-height:95%}.layout-xl-row>.flex-xl-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:95%;max-height:100%;box-sizing:border-box}.layout-xl-column>.flex-xl-95{max-height:95%}.flex-xl-100,.layout-xl-column>.flex-xl-95{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;box-sizing:border-box}.flex-xl-100{max-height:100%}.layout-column>.flex-xl-100,.layout-row>.flex-xl-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-row>.flex-xl-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-row>.flex-xl-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-column>.flex-xl-33{-webkit-box-flex:1;-webkit-flex:1 1 33.33%;flex:1 1 33.33%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-column>.flex-xl-66{-webkit-box-flex:1;-webkit-flex:1 1 66.66%;flex:1 1 66.66%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-xl-column>.flex-xl-100,.layout-xl-row>.flex-xl-100{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:100%;box-sizing:border-box}.layout-xl-row>.flex-xl-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:33.33%;max-height:100%;box-sizing:border-box}.layout-xl-row>.flex-xl-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:66.66%;max-height:100%;box-sizing:border-box}.layout-xl-row>.flex{min-width:0}.layout-xl-column>.flex-xl-33{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:33.33%;box-sizing:border-box}.layout-xl-column>.flex-xl-66{-webkit-box-flex:1;-webkit-flex:1 1 100%;flex:1 1 100%;max-width:100%;max-height:66.66%;box-sizing:border-box}.layout-xl-column>.flex{min-height:0}.layout-xl,.layout-xl-column,.layout-xl-row{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:flex}.layout-xl-column{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column}.layout-xl-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;flex-direction:row}.hide-gt-lg:not(.show-gt-xs):not(.show-gt-sm):not(.show-gt-md):not(.show-gt-lg):not(.show-xl):not(.show),.hide-gt-md:not(.show-gt-xs):not(.show-gt-sm):not(.show-gt-md):not(.show-gt-lg):not(.show-xl):not(.show),.hide-gt-sm:not(.show-gt-xs):not(.show-gt-sm):not(.show-gt-md):not(.show-gt-lg):not(.show-xl):not(.show),.hide-gt-xs:not(.show-gt-xs):not(.show-gt-sm):not(.show-gt-md):not(.show-gt-lg):not(.show-xl):not(.show),.hide-xl:not(.show-xl):not(.show-gt-lg):not(.show-gt-md):not(.show-gt-sm):not(.show-gt-xs):not(.show),.hide:not(.show-gt-xs):not(.show-gt-sm):not(.show-gt-md):not(.show-gt-lg):not(.show-xl):not(.show){display:none}}@media print{.hide-print:not(.show-print):not(.show){display:none!important}} \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/search/search.html b/repo_health/index/static/client/src/components/search/search.html index 6e6a3d6..5be65d0 100644 --- a/repo_health/index/static/client/src/components/search/search.html +++ b/repo_health/index/static/client/src/components/search/search.html @@ -1,15 +1,13 @@ -
-
+
+

Github Url

-
- -
-
-
- + + + +
+ Get Statistics
-
-
+
\ No newline at end of file diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index 327d744..0c00449 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -12,6 +12,7 @@ */ import angular from 'angular'; +import ngMaterial from 'angular-material'; import uiRouter from 'angular-ui-router'; import components from 'components/components.module.js'; @@ -20,6 +21,7 @@ import 'global.css'; export const main = angular.module('repo-health', [ uiRouter, + ngMaterial, components ]) .config(($locationProvider, $urlRouterProvider) => { diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index d693d41..b1eb9ad 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -7,6 +7,9 @@ "license": "MIT", "dependencies": { "angular": "^1.6.2", + "angular-animate": "^1.6.2", + "angular-aria": "^1.6.2", + "angular-material": "^1.1.3", "angular-ui-router": "^0.4.2", "jquery": "^3.1.0" }, diff --git a/repo_health/index/templates/index.html b/repo_health/index/templates/index.html index 216fc9c..4e6e800 100644 --- a/repo_health/index/templates/index.html +++ b/repo_health/index/templates/index.html @@ -1,20 +1,20 @@ {% load static %} - - - - Repo Health Assessment - - -
-

Repo Health Assessment

-
-
-
-
- + + + + Repo Health Assessment + + +
+

Repo Health Assessment

+
+
+
+
+ - - + + From 38707e84b606386b8cc31f1a4ad590ab8dba47d3 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Tue, 28 Feb 2017 22:55:27 -0600 Subject: [PATCH 38/99] Add some comments around average pr lifetime aggregation. --- repo_health/gh_projects/serializers/GhProjectSerializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repo_health/gh_projects/serializers/GhProjectSerializer.py b/repo_health/gh_projects/serializers/GhProjectSerializer.py index 8cc30a6..0268782 100644 --- a/repo_health/gh_projects/serializers/GhProjectSerializer.py +++ b/repo_health/gh_projects/serializers/GhProjectSerializer.py @@ -41,7 +41,7 @@ def __init__(self, *args, **kwargs): repo = args[0].first() if repo is not None: commits = (repo.commits_m2m.all() | repo.commits_fk.all()).order_by('-created_at') - commit_users = GhUser.objects.filter(commits__in=commits).distinct() + commit_users = GhUser.objects.filter(authored_commits__in=commits).distinct() self._commits_count = commits.count() self._contribs_count = commit_users.count() self._latest_commit = commits.first().created_at From 9c7ee960f856083e865391c2526f7647879f3290 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Tue, 28 Feb 2017 22:55:46 -0600 Subject: [PATCH 39/99] Add some comments around average pr lifetime aggregation. Rest of files. --- docs/rest_api/PullRequests.md | 2 -- .../GhPullRequestStatsSerializer.py | 28 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/docs/rest_api/PullRequests.md b/docs/rest_api/PullRequests.md index 0f2aa88..39b3725 100644 --- a/docs/rest_api/PullRequests.md +++ b/docs/rest_api/PullRequests.md @@ -18,8 +18,6 @@ A GET request is made to: "not_maintainer_prs": int, "avg_comment_per_pr": float, "prs_from_outside_org": int, - "maintainers_count: int, - "is_org": bool } ``` diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index a220c3e..26ab651 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -12,10 +12,10 @@ import datetime import calendar -from django.db import models +from django.db import models as m from rest_framework import serializers as s from repo_health.gh_users.models import GhUser -from ..models import GhPullRequestHistory, GhPullRequest +from ..models import GhPullRequestHistory class GhPullRequestStatsSerializer(s.Serializer): @@ -51,7 +51,7 @@ def __init__(self, *args, **kwargs): self._contrib_most_prs = GhUser.objects.filter( pull_requests__base_repo=repo, ).annotate( - contrib_prs=models.Count('pull_requests') + contrib_prs=m.Count('pull_requests') ).order_by('-contrib_prs').first() self._maintainers = repo.maintainers.all() @@ -88,26 +88,26 @@ def get_maintainers_count(self, repo): return self._maintainers.count() def get_prs_no_comments(self, repo): - return repo.prs_to.annotate(comments_count=models.Count('comments')).filter(comments_count=0).count() + return repo.prs_to.annotate(comments_count=m.Count('comments')).filter(comments_count=0).count() def get_avg_lifetime(self, repo): - avg = 0 - if repo.pr_count > 0: + avg = closed = 0 + # An inefficient way to calculate average but I haven't got the aggregation to work + if repo.pr_count > 0: # prevent divide by zero td = datetime.timedelta() for p in repo.prs_to.all(): if p.closed_at: + closed += 1 td += p.closed_at - p.created_at - avg = (td / repo.pr_count).days + avg = (td / closed).days + # Save this code to hopefully aggregate the average at the database level at sometime. # agg = repo.prs_to \ - # .annotate(closed_at=models.When(history__action=GhPullRequestHistory.CLOSED_ACTION, then=models.F('history__created_at'))) \ - # .annotate(created_at=models.When(history__action=GhPullRequestHistory.OPENED_ACTION, then=models.F('history__created_at')))\ - # .annotate(elapsed=models.F('closed_at') - models.F('created_at'))\ + # .annotate(closed_at=m.Case(m.When(m.Q(history__action=GhPullRequestHistory.CLOSED_ACTION) & m.Q(history__created_at__isnull=False)), then=m.F('history__created_at'))) \ + # .annotate(created_at=m.Case(m.When(m.Q(history__action=GhPullRequestHistory.OPENED_ACTION) & m.Q(history__created_at__isnull=False)), then=m.F('history__created_at'))) \ + # .annotate(elapsed=m.F('closed_at')) \ # .values('created_at', 'closed_at', 'id', 'elapsed') - # print(agg) - # for a in agg: - # if a.get('elapsed'): - # print("Has elapsed:" + a) + # .aggregate(life=m.Max('closed_at', output_field=m.DateTimeField())) return avg class Meta: From 53b4c175136670940ec8a07bd2cf9957a24b84db Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 1 Mar 2017 00:10:46 -0600 Subject: [PATCH 40/99] Final metrics for prs. --- docs/rest_api/PullRequests.md | 4 ++-- repo_health/gh_projects/tests.py | 14 +++++++++---- repo_health/gh_projects/views.py | 2 ++ .../GhPullRequestStatsSerializer.py | 20 +++++++++++++++---- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/docs/rest_api/PullRequests.md b/docs/rest_api/PullRequests.md index 39b3725..41fdced 100644 --- a/docs/rest_api/PullRequests.md +++ b/docs/rest_api/PullRequests.md @@ -16,8 +16,8 @@ A GET request is made to: "prs_no_comments": int, "avg_lifetime": str, "not_maintainer_prs": int, - "avg_comment_per_pr": float, - "prs_from_outside_org": int, + "avg_comment_per_pr": float, //3 decimal places of precisions + "prs_from_outside_org": int | null, // Null if the repo is not part of org } ``` diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 58a39e5..b38afd5 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -89,17 +89,23 @@ def test_api_get_project_not_found(self): }) self.assertTrue(status.is_client_error(r_with_bad_key.status_code)) + # test with no param + r_with_no_param = self.client.get('/api/v1/gh-projects') + self.assertTrue(status.is_client_error(r_with_no_param.status_code)) + def test_get_pr_stats(self): r = self.client.get('/api/v1/gh-projects/%d/pull-requests' % self.django.id) self.assertTrue(status.is_success(r.status_code), 'Status code was: %d' % r.status_code) + # Check for a few custom fields of the serialozer self.assertTrue(r.data['pr_count'] and isinstance(r.data['pr_count'], int)) self.assertTrue(r.data['prs_last_year'] and isinstance(r.data['prs_last_year'], list)) - self.assertTrue(r.data.get('latest_pr_created_at') and isinstance(r.data['latest_pr_created_at'], datetime.datetime)) + self.assertTrue( + r.data.get('latest_pr_created_at') and isinstance(r.data['latest_pr_created_at'], datetime.datetime) + ) self.assertTrue(r.data['contrib_most_prs'] and isinstance(r.data['contrib_most_prs'], str)) - self.assertTrue(r.data.get('prs_no_maintainer_comments') and isinstance(r.data['prs_no_maintainer_comments'], int)) + self.assertTrue( + r.data.get('prs_no_maintainer_comments') and isinstance(r.data['prs_no_maintainer_comments'], int)) - import pprint as pp - pp.pprint(r.data) # Test a repo with no prs to be sure no errors are thrown self.client.get('/api/v1/gh-projects/%d/pull-requests' % self.project_no_prs.id) diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index fb618ab..6b924f3 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -29,6 +29,8 @@ class GhProjectViewSet(ListModelMixin, GenericViewSet): filter_fields = ('owner__login', 'name') def list(self, r, *args, **kwargs): + if not r.GET.get('name') or not r.GET.get('owner__login'): + raise NotFound('Repo not found', HTTP_404_NOT_FOUND) response = super().list(r, *args, **kwargs) if len(response.data) is not 1: raise NotFound('Repo not found', HTTP_404_NOT_FOUND) diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 26ab651..2828d93 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -33,9 +33,9 @@ class GhPullRequestStatsSerializer(s.Serializer): maintainers_count = s.SerializerMethodField() prs_no_comments = s.SerializerMethodField() avg_lifetime = s.SerializerMethodField() - # not_maintainer_prs = s.SerializerMethodField() - # avg_comment_per_pr = s.SerializerMethodField() - # prs_from_outside_org = s.SerializerMethodField() + not_maintainer_prs = s.SerializerMethodField() + avg_comment_per_pr = s.SerializerMethodField() + prs_from_outside_org = s.SerializerMethodField() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -101,7 +101,7 @@ def get_avg_lifetime(self, repo): td += p.closed_at - p.created_at avg = (td / closed).days - # Save this code to hopefully aggregate the average at the database level at sometime. + # Save this code to hopefully aggregate the average at the database level sometime. # agg = repo.prs_to \ # .annotate(closed_at=m.Case(m.When(m.Q(history__action=GhPullRequestHistory.CLOSED_ACTION) & m.Q(history__created_at__isnull=False)), then=m.F('history__created_at'))) \ # .annotate(created_at=m.Case(m.When(m.Q(history__action=GhPullRequestHistory.OPENED_ACTION) & m.Q(history__created_at__isnull=False)), then=m.F('history__created_at'))) \ @@ -110,6 +110,18 @@ def get_avg_lifetime(self, repo): # .aggregate(life=m.Max('closed_at', output_field=m.DateTimeField())) return avg + def get_not_maintainer_prs(self, repo): + return repo.prs_to.exclude(user__in=self._maintainers).count() + + def get_avg_comment_per_pr(self, repo): + avg_agg = repo.prs_to.annotate(comment_count=m.Count('comments')) \ + .aggregate(avg=m.Avg('comment_count')) + return avg_agg['avg'] + + def get_prs_from_outside_org(self, repo): + if repo.is_owned_by_org(): + return repo.prs_to.exclude(user__organizations=repo.owner).count() + class Meta: model = 'gh_projects.GhProject' fields = ('pr_count', ) From e4072b8811f49b5264521ccc0d27120992112888 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Sat, 4 Mar 2017 17:21:31 -0600 Subject: [PATCH 41/99] More work on repos --- .../src/components/components.module.js | 4 +- .../repo-details/repo-details.component.js | 40 +++++++++++ .../components/repo-details/repo-details.html | 20 ++++++ .../repo-details/repo-details.module.js | 38 +++++++++++ .../repo-details/repo-details.service.js | 40 +++++++++++ .../repo-details/repo-details.spec.js | 0 .../src/components/search/search.component.js | 20 +++++- .../client/src/components/search/search.html | 43 ++++++++---- .../index/static/client/src/main.component.js | 26 ++++++++ .../index/static/client/src/main.module.js | 16 ++++- .../index/static/client/src/resources.js | 66 +++++++++++++++++++ repo_health/index/static/package.json | 1 + repo_health/index/templates/index.html | 9 +-- 13 files changed, 301 insertions(+), 22 deletions(-) create mode 100644 repo_health/index/static/client/src/components/repo-details/repo-details.component.js create mode 100644 repo_health/index/static/client/src/components/repo-details/repo-details.html create mode 100644 repo_health/index/static/client/src/components/repo-details/repo-details.module.js create mode 100644 repo_health/index/static/client/src/components/repo-details/repo-details.service.js create mode 100644 repo_health/index/static/client/src/components/repo-details/repo-details.spec.js create mode 100644 repo_health/index/static/client/src/main.component.js create mode 100644 repo_health/index/static/client/src/resources.js diff --git a/repo_health/index/static/client/src/components/components.module.js b/repo_health/index/static/client/src/components/components.module.js index 7ae1641..b82e76a 100644 --- a/repo_health/index/static/client/src/components/components.module.js +++ b/repo_health/index/static/client/src/components/components.module.js @@ -11,10 +11,12 @@ */ import search from './search/search.module'; +import repoDetails from './repo-details/repo-details.module'; const components = angular .module('components', [ - search + search, + repoDetails ]) .name; diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js new file mode 100644 index 0000000..ce670d0 --- /dev/null +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -0,0 +1,40 @@ +/* +* search.component.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the creation of the search component. +*/ + +import template from './repo-details'; + +const repoDetailsComponent = { + template, + controller: class repoDetailsComponent { + + loadingRepo = true; + details = null; + + constructor(RepoDetailsService, $state, $stateParams) { + 'ngInject'; + Object.assign(this, { RepoDetailsService, $state, $stateParams }); + } + + $onInit() { + this.getStats(); + } + + getStats() { + this.RepoDetailsService.getStats(this.$stateParams).then(details => { + this.loadingRepo = false; + this.details = details; + }, () => this.$state.go('search')); + } + } +}; + +export default repoDetailsComponent; diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.html b/repo_health/index/static/client/src/components/repo-details/repo-details.html new file mode 100644 index 0000000..5a09eb5 --- /dev/null +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.html @@ -0,0 +1,20 @@ +
+ Loading your repository... Please wait... +
+ +
+
+ + + +
+

{{item.what}}

+

{{item.who}}

+

{{item.notes}}

+
+ Respond + +
+
+{{$ctrl.details.name}} +
diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.module.js b/repo_health/index/static/client/src/components/repo-details/repo-details.module.js new file mode 100644 index 0000000..64d1f94 --- /dev/null +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.module.js @@ -0,0 +1,38 @@ +/* +* repo-details.module.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the module definition for the repo-details component +*/ + +import uiRouter from 'angular-ui-router'; +import repoDetailsComponent from './repo-details.component'; +import repoDetailsService from './repo-details.service'; + +const components = angular + .module('components.repo-details', [uiRouter]) + .service('RepoDetailsService', repoDetailsService) + .component('repoDetails', repoDetailsComponent) + .config($stateProvider => { + 'ngInject'; + + $stateProvider.state('repo-details', { + url: '/repo-details?name&owner__login', + template: '' + }) + }) + .run($api => { + 'ngInject'; + $api.add({ + resource: 'repo', + url: '/' + }); + }) + .name; + +export default components; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js new file mode 100644 index 0000000..c3d7b04 --- /dev/null +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js @@ -0,0 +1,40 @@ +/* +* repo-details.service.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the module definition for the repo-details service +*/ + +class RepoDetailsService { + + repoDetails = null; + + constructor ($repo){ + 'ngInject'; + + Object.assign(this, { $repo }); + } + + getNameAndOwnerFromUrl(url = '') { + const pathArray = url.split('/'); + const name = pathArray.pop(); + const owner__login = pathArray.pop(); + return name && owner__login ? { owner__login, name } : undefined; + } + + getStats(params) { + if (this.repoDetails) { + return Promise.resolve(this.repoDetails); + } else { + return this.$repo.get('repo', params).then(details => (this.repoDetails = details)); + } + } + +} + +export default RepoDetailsService; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js new file mode 100644 index 0000000..e69de29 diff --git a/repo_health/index/static/client/src/components/search/search.component.js b/repo_health/index/static/client/src/components/search/search.component.js index 37711db..2bd1673 100644 --- a/repo_health/index/static/client/src/components/search/search.component.js +++ b/repo_health/index/static/client/src/components/search/search.component.js @@ -16,8 +16,26 @@ const searchComponent = { template, controller: class searchComponent { + loadingRepo = false; + error = null; + + constructor(RepoDetailsService, $state, $stateParams) { + 'ngInject'; + Object.assign(this, { RepoDetailsService, $state, $stateParams }); + } + getStats() { - // Add service to get the statistics + const params = this.RepoDetailsService.getNameAndOwnerFromUrl(this.githubUrl); + if (params) { + this.loadingRepo = true + this.error = null; + this.RepoDetailsService.getStats(params).then(() => { + this.$state.go('repo-details', params); + }, () => { + this.error = 'This repo does not exist'; + this.loadingRepo = false; + }); + } } } }; diff --git a/repo_health/index/static/client/src/components/search/search.html b/repo_health/index/static/client/src/components/search/search.html index 5be65d0..9429bb3 100644 --- a/repo_health/index/static/client/src/components/search/search.html +++ b/repo_health/index/static/client/src/components/search/search.html @@ -1,13 +1,34 @@ -
- -
-

Github Url

- - - -
- Get Statistics -
-
+
+ +
+ + + + Error + This repo does not exist + + + +
+
+ Loading your repository... Please wait... +
+ +
+
+ +
+ +
+

Github Url

+ + + +
+ Get Statistics +
+
+
+
\ No newline at end of file diff --git a/repo_health/index/static/client/src/main.component.js b/repo_health/index/static/client/src/main.component.js new file mode 100644 index 0000000..579af90 --- /dev/null +++ b/repo_health/index/static/client/src/main.component.js @@ -0,0 +1,26 @@ +/* +* main.component.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the creation of the search component. +*/ + +const template = ` +
+

Repo Health Assessment

+
+
+
+
+`; + +const mainComponent = { + template +}; + +export default mainComponent; diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index 0c00449..fd57688 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -14,7 +14,9 @@ import angular from 'angular'; import ngMaterial from 'angular-material'; import uiRouter from 'angular-ui-router'; +import resources from './resources'; import components from 'components/components.module.js'; +import mainComponent from './main.component'; //Styles import 'global.css'; @@ -22,12 +24,22 @@ import 'global.css'; export const main = angular.module('repo-health', [ uiRouter, ngMaterial, - components + components, + resources ]) - .config(($locationProvider, $urlRouterProvider) => { + .component('main', mainComponent) + .config(($locationProvider, $urlRouterProvider, $mdThemingProvider) => { 'ngInject'; $locationProvider.hashPrefix(''); $urlRouterProvider.otherwise('/search'); + + // Set-up themes + $mdThemingProvider.theme('error').backgroundPalette('red').dark(); + + $mdThemingProvider.theme('default') + .primaryPalette('light-blue') + .accentPalette('orange') + .backgroundPalette('blue-grey'); }) .name; diff --git a/repo_health/index/static/client/src/resources.js b/repo_health/index/static/client/src/resources.js new file mode 100644 index 0000000..5d8a8b6 --- /dev/null +++ b/repo_health/index/static/client/src/resources.js @@ -0,0 +1,66 @@ +import ngResource from 'angular-resource'; + +const resources = angular.module('app.resources', [ ngResource ]) + .value('$apiUrl', '/api/v1/gh-projects') + + .factory('$api', function($resource, $apiUrl) { + 'ngInject'; + + const idAndVerb = { + id: '@id', + verb: '@verb' + }; + + const api = { + idAndVerb, + + add(config) { + var params; + var url; + + const orig = angular.copy(idAndVerb); + params = angular.extend(orig, config.params); + url = $apiUrl + config.url + '/:id/:verb'; + + api[config.resource] = $resource(url, params); + } + }; + + return api; + }) + + .provider('$repo', { + + list(resource, query){ + return $repo => $repo.list(resource, query); + }, + + get(resource) { + return $repo => $repo.get(resource); + }, + + $get($q, $api) { + + const repo = { + + list(resource, query) { + let queryObject = {}; + + if (angular.isObject(query)) { + queryObject = angular.extend(queryObject, query); + } + + return $api[resource].query(queryObject).$promise; + }, + + get(resource, params) { + return $api[resource].get(params).$promise; + } + }; + + return repo; + } + }) + .name; + +export default resources; diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index b1eb9ad..ec4438e 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -10,6 +10,7 @@ "angular-animate": "^1.6.2", "angular-aria": "^1.6.2", "angular-material": "^1.1.3", + "angular-resource": "^1.6.2", "angular-ui-router": "^0.4.2", "jquery": "^3.1.0" }, diff --git a/repo_health/index/templates/index.html b/repo_health/index/templates/index.html index 4e6e800..7f8dc95 100644 --- a/repo_health/index/templates/index.html +++ b/repo_health/index/templates/index.html @@ -6,13 +6,8 @@ Repo Health Assessment - -
-

Repo Health Assessment

-
-
-
-
+ +
From b508aa58b18cc38e88a39cda671913eb29e50d07 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Sat, 4 Mar 2017 19:00:13 -0600 Subject: [PATCH 42/99] Added basic stats --- .../components/repo-details/repo-details.html | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.html b/repo_health/index/static/client/src/components/repo-details/repo-details.html index 5a09eb5..8ea2d1c 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.html +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.html @@ -4,17 +4,29 @@
- - - -
-

{{item.what}}

-

{{item.who}}

-

{{item.notes}}

-
- Respond - -
-
-{{$ctrl.details.name}} + + + + + {{::$ctrl.details.name}} + {{::$ctrl.details.description}} + + + +
+
Language: {{$ctrl.details.language}}
+
Contributions: {{$ctrl.details.contribs_count}}
+
+ +
+
Watchers: {{$ctrl.details.watchers_count}}
+
Commits: {{$ctrl.details.commits_count}}
+
+ +
+
Milestones: {{$ctrl.details.milestones_count}}
+
Forks: {{$ctrl.details.forks_count}}
+
+
+
From a1e9a39cec53894cad1dfe845482aaf3979106b9 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Sat, 4 Mar 2017 22:54:39 -0600 Subject: [PATCH 43/99] Added some tests --- .../repo-details/repo-details.spec.js | 61 +++++++++++++++++++ .../src/components/search/search.spec.js | 37 ++++++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index e69de29..fdbccb6 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -0,0 +1,61 @@ +/* +* search.spec.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* @bparish628 +* +* This is the test file for the search component +*/ + +describe('Repo Details', () => { + let $rootScope; + + beforeEach(angular.mock.module( + 'app.resources', + 'components.search', + 'components.repo-details') + ); + + describe('RepoDetailsController', () => { + let $componentController; + let controller; + + beforeEach(inject(($injector) => { + $componentController = $injector.get('$componentController'); + $rootScope = $injector.get('$rootScope'); + controller = $componentController('repoDetails'); + })); + + describe('constructor', () => { + it('should setup the controller', () => { + expect(controller).toBeDefined; + }); + + it('should setup loadingRepo and details', () => { + expect(controller.loadingRepo).toBeTrue; + expect(controller.details).toBeNull; + }); + + it('should setup RepoDetailsService, $state, $stateParams', () => { + expect(controller.RepoDetailsService).toBeOk; + expect(controller.$state).toBeOk; + expect(controller.$stateParams).toBeOk; + }); + }); + + describe('getStats', () => { + it('should make a call to service', async () => { + spyOn(controller.RepoDetailsService, 'getStats').and.returnValue(Promise.resolve({ name: 'cakephp' })); + expect(controller.RepoDetailsService.getStats).not.toHaveBeenCalled; + controller.getStats(); + $rootScope.$apply(); + expect(controller.loadingRepo).toBeFalse; + expect(controller.details).toBe({ name: 'cakephp' }); + expect(controller.RepoDetailsService.getStats).toHaveBeenCalled; + }); + }); + }); +}); \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/search/search.spec.js b/repo_health/index/static/client/src/components/search/search.spec.js index 75db1b0..3934db8 100644 --- a/repo_health/index/static/client/src/components/search/search.spec.js +++ b/repo_health/index/static/client/src/components/search/search.spec.js @@ -11,7 +11,11 @@ */ describe('Search', () => { - beforeEach(angular.mock.module('components.search')); + beforeEach(angular.mock.module( + 'app.resources', + 'components.search', + 'components.repo-details') + ); describe('SearchController', () => { let $componentController; @@ -26,11 +30,38 @@ describe('Search', () => { it('should setup the controller', () => { expect(controller).toBeDefined; }); + it('should setup loadingRepo and error', () => { + expect(controller.loadingRepo).toBeFalse; + expect(controller.error).toBeNull; + }); }); describe('getStats', () => { - it('should return the stats', () => { - //Add tests when function is implemented + beforeEach(() => { + spyOn(controller.RepoDetailsService, 'getStats').and.returnValue(Promise.resolve({ name: 'cakephp' })); + }); + + it('should not make a call if url is invalid', () => { + controller.githubUrl = 'This not a url'; + controller.getStats(); + expect(controller.loadingRepo).toBeTrue; + expect(controller.RepoDetailsService.getStats).not.toHaveBeenCalled; + }); + + it('should make a call to getStats on the service', async () => { + controller.githubUrl = 'https://github.com/cakephp/cakephp'; + controller.getStats(); + expect(controller.loadingRepo).toBeTrue; + expect(controller.RepoDetailsService.getStats).toHaveBeenCalled; + }); + + it('should set an error if it fails', async () => { + spyOn(controller.RepoDetailsService, 'getStats').and.returnValue(Promise.reject('error')); + controller.githubUrl = 'https://github.com/cakephp/cakephp'; + controller.getStats(); + expect(controller.loadingRepo).toBeFalse; + expect(controller.error).toBe('This repo does not exist'); + expect(controller.RepoDetailsService.getStats).toHaveBeenCalled; }); }); }); From a063386966db1d37cc76047bb5ec4ceadfe1111d Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Sat, 4 Mar 2017 23:01:00 -0600 Subject: [PATCH 44/99] fixed a test --- .../client/src/components/repo-details/repo-details.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index fdbccb6..42caea8 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -1,5 +1,5 @@ /* -* search.spec.js - (C) Copyright - 2017 +* repo-details.spec.js - (C) Copyright - 2017 * This software is copyrighted to contributors listed in CONTRIBUTIONS.md. * * SPDX-License-Identifier: MIT From 6c4d34b9fa632e78b228dda6dbb4acb818ca1291 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Mon, 13 Mar 2017 16:25:08 -0500 Subject: [PATCH 45/99] Fixed up the tests --- .../repo-details/repo-details.service.js | 13 +++- .../repo-details/repo-details.spec.js | 77 +++++++++++++++---- .../client/src/components/search/search.html | 2 +- .../src/components/search/search.spec.js | 47 ++++++----- repo_health/index/static/karma.conf.js | 6 +- repo_health/index/static/package.json | 2 +- 6 files changed, 107 insertions(+), 40 deletions(-) diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js index c3d7b04..e3c01b2 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js @@ -14,14 +14,19 @@ class RepoDetailsService { repoDetails = null; - constructor ($repo){ + constructor ($repo, $q){ 'ngInject'; - Object.assign(this, { $repo }); + Object.assign(this, { $repo, $q }); } + /* Gets the last two strings on a url */ getNameAndOwnerFromUrl(url = '') { - const pathArray = url.split('/'); + if (url.search('github.com') == -1) { + return; + } + + const pathArray = url.replace(/.*github.com\//, '').split('/'); const name = pathArray.pop(); const owner__login = pathArray.pop(); return name && owner__login ? { owner__login, name } : undefined; @@ -29,7 +34,7 @@ class RepoDetailsService { getStats(params) { if (this.repoDetails) { - return Promise.resolve(this.repoDetails); + return this.$q.resolve(this.repoDetails); } else { return this.$repo.get('repo', params).then(details => (this.repoDetails = details)); } diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index 42caea8..50a393d 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -10,10 +10,13 @@ * This is the test file for the search component */ +const module = angular.mock.module; + describe('Repo Details', () => { let $rootScope; + let $q; - beforeEach(angular.mock.module( + beforeEach(module( 'app.resources', 'components.search', 'components.repo-details') @@ -26,35 +29,83 @@ describe('Repo Details', () => { beforeEach(inject(($injector) => { $componentController = $injector.get('$componentController'); $rootScope = $injector.get('$rootScope'); + $q = $injector.get('$q'); controller = $componentController('repoDetails'); })); describe('constructor', () => { it('should setup the controller', () => { - expect(controller).toBeDefined; + expect(controller).toBeDefined(); }); it('should setup loadingRepo and details', () => { - expect(controller.loadingRepo).toBeTrue; - expect(controller.details).toBeNull; + expect(controller.loadingRepo).toBeTruthy(); + expect(controller.details).toBeNull(); }); it('should setup RepoDetailsService, $state, $stateParams', () => { - expect(controller.RepoDetailsService).toBeOk; - expect(controller.$state).toBeOk; - expect(controller.$stateParams).toBeOk; + expect(controller.RepoDetailsService).toBeDefined(); + expect(controller.$state).toBeDefined(); + expect(controller.$stateParams).toBeDefined(); }); }); describe('getStats', () => { - it('should make a call to service', async () => { - spyOn(controller.RepoDetailsService, 'getStats').and.returnValue(Promise.resolve({ name: 'cakephp' })); - expect(controller.RepoDetailsService.getStats).not.toHaveBeenCalled; + it('should make a call to service', () => { + spyOn(controller.RepoDetailsService, 'getStats').and.returnValue($q.resolve({ name: 'cakephp' })); + expect(controller.RepoDetailsService.getStats).not.toHaveBeenCalled(); controller.getStats(); $rootScope.$apply(); - expect(controller.loadingRepo).toBeFalse; - expect(controller.details).toBe({ name: 'cakephp' }); - expect(controller.RepoDetailsService.getStats).toHaveBeenCalled; + expect(controller.loadingRepo).toBeFalsy(); + expect(controller.details).toEqual({ name: 'cakephp' }); + expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); + }); + }); + }); + + describe('RepoDetailsService', () => { + let RepoDetailsService; + let $httpBackend; + let $apiUrl; + + beforeEach(inject(($injector) => { + $rootScope = $injector.get('$rootScope'); + $q = $injector.get('$q'); + $httpBackend = $injector.get('$httpBackend'); + $apiUrl = $injector.get('$apiUrl'); + RepoDetailsService = $injector.get('RepoDetailsService'); + })); + + describe('getNameAndOwnerFromUrl', () => { + it('should return name and owner', () => { + expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name/repo')).toEqual({ name: 'repo', owner__login: 'name' }); + }); + + it('should return undefined', () => { + expect(RepoDetailsService.getNameAndOwnerFromUrl()).toBeUndefined(); + expect(RepoDetailsService.getNameAndOwnerFromUrl('not a url')).toBeUndefined(); + expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name')).toBeUndefined(); + }); + }); + + describe('getStats', () => { + it('should return a promise if repoDetails exists', () => { + RepoDetailsService.repoDetails = { name: 'cakephp', watchers: 123 }; + RepoDetailsService.getStats().then(details => { + expect(details).toEqual(RepoDetailsService.repoDetails); + }); + $rootScope.$apply(); + }); + + it('should set repoDetails if it doesn\'t exist', () => { + $httpBackend.when('GET', `${$apiUrl}?name=cakephp&owner__login=cakephp`).respond(200, { name: 'cakephp', watchers: 15 }); + RepoDetailsService.getStats({ name: 'cakephp', owner__login: 'cakephp' }).then(details => { + expect(details).toEqual(RepoDetailsService.repoDetails); + }); + $httpBackend.flush(); + $rootScope.$apply(); + expect(RepoDetailsService.repoDetails.name).toEqual('cakephp'); + expect(RepoDetailsService.repoDetails.watchers).toEqual(15); }); }); }); diff --git a/repo_health/index/static/client/src/components/search/search.html b/repo_health/index/static/client/src/components/search/search.html index 9429bb3..7797e71 100644 --- a/repo_health/index/static/client/src/components/search/search.html +++ b/repo_health/index/static/client/src/components/search/search.html @@ -5,7 +5,7 @@ Error - This repo does not exist + {{$ctrl.error}} diff --git a/repo_health/index/static/client/src/components/search/search.spec.js b/repo_health/index/static/client/src/components/search/search.spec.js index 3934db8..b44064c 100644 --- a/repo_health/index/static/client/src/components/search/search.spec.js +++ b/repo_health/index/static/client/src/components/search/search.spec.js @@ -10,58 +10,69 @@ * This is the test file for the search component */ +const module = angular.mock.module; + describe('Search', () => { - beforeEach(angular.mock.module( + let sandbox; + + beforeEach(module( 'app.resources', - 'components.search', - 'components.repo-details') + 'components.repo-details', + 'components.search') ); describe('SearchController', () => { let $componentController; + let $rootScope; + let RepoDetailsService; + let $q; let controller; beforeEach(inject(($injector) => { $componentController = $injector.get('$componentController'); + $rootScope = $injector.get('$rootScope'); + $q = $injector.get('$q'); + RepoDetailsService = $injector.get('RepoDetailsService'); controller = $componentController('search'); })); describe('constructor', () => { it('should setup the controller', () => { - expect(controller).toBeDefined; + expect(controller).toBeDefined(); }); it('should setup loadingRepo and error', () => { - expect(controller.loadingRepo).toBeFalse; - expect(controller.error).toBeNull; + expect(controller.loadingRepo).toBeFalsy(); + expect(controller.error).toBeNull(); }); }); describe('getStats', () => { - beforeEach(() => { - spyOn(controller.RepoDetailsService, 'getStats').and.returnValue(Promise.resolve({ name: 'cakephp' })); - }); + let getStats; it('should not make a call if url is invalid', () => { + spyOn(controller.RepoDetailsService, 'getStats'); controller.githubUrl = 'This not a url'; controller.getStats(); expect(controller.loadingRepo).toBeTrue; - expect(controller.RepoDetailsService.getStats).not.toHaveBeenCalled; + expect(controller.RepoDetailsService.getStats).not.toHaveBeenCalled(); }); - it('should make a call to getStats on the service', async () => { + it('should make a call to getStats on the service', () => { + spyOn(controller.RepoDetailsService, 'getStats').and.returnValue($q.resolve({ name: 'cakephp' })); controller.githubUrl = 'https://github.com/cakephp/cakephp'; controller.getStats(); - expect(controller.loadingRepo).toBeTrue; - expect(controller.RepoDetailsService.getStats).toHaveBeenCalled; + expect(controller.loadingRepo).toBeTruthy(); + expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); }); - it('should set an error if it fails', async () => { - spyOn(controller.RepoDetailsService, 'getStats').and.returnValue(Promise.reject('error')); + it('should set an error if it fails', () => { + spyOn(controller.RepoDetailsService, 'getStats').and.returnValue($q.reject('error')); controller.githubUrl = 'https://github.com/cakephp/cakephp'; controller.getStats(); - expect(controller.loadingRepo).toBeFalse; - expect(controller.error).toBe('This repo does not exist'); - expect(controller.RepoDetailsService.getStats).toHaveBeenCalled; + $rootScope.$apply(); + expect(controller.loadingRepo).toBeFalsy(); + expect(controller.error).toEqual('This repo does not exist'); + expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); }); }); }); diff --git a/repo_health/index/static/karma.conf.js b/repo_health/index/static/karma.conf.js index c88dcd6..3735899 100644 --- a/repo_health/index/static/karma.conf.js +++ b/repo_health/index/static/karma.conf.js @@ -27,7 +27,7 @@ module.exports = (config) => { ], plugins: [ require('karma-jasmine'), - require('karma-chrome-launcher'), + require('karma-phantomjs-launcher'), require('karma-webpack') ], preprocessors: { @@ -38,8 +38,8 @@ module.exports = (config) => { colors: true, logLevel: config.LOG_INFO, autoWatch: true, - browsers: ['Chrome'], - singleRun: true, + browsers: ['PhantomJS'], + singleRun: false, concurrency: Infinity, }); }; \ No newline at end of file diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index ec4438e..57b1dd5 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -31,8 +31,8 @@ "html-webpack-plugin": "^2.28.0", "jasmine-core": "^2.5.2", "karma": "^1.5.0", - "karma-chrome-launcher": "^2.0.0", "karma-jasmine": "^1.1.0", + "karma-phantomjs-launcher": "^1.0.4", "karma-webpack": "^2.0.2", "progress-bar-webpack-plugin": "^1.9.3", "style-loader": "^0.13.1", From 4f31457a1f7baec32cde83a3bb1dc17e11ca4c95 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Mon, 13 Mar 2017 22:37:14 -0500 Subject: [PATCH 46/99] Fix indentation --- .../client/src/components/repo-details/repo-details.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index 50a393d..e725501 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -63,7 +63,7 @@ describe('Repo Details', () => { }); }); - describe('RepoDetailsService', () => { + describe('RepoDetailsService', () => { let RepoDetailsService; let $httpBackend; let $apiUrl; From 688ae14c2b113e7ef9dbcdd7860440e7a506f292 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sat, 18 Mar 2017 23:21:02 -0500 Subject: [PATCH 47/99] Setup of named views for async loading of pr stats. --- .../src/components/components.module.js | 5 ++- .../pull-req-stats.component.js | 30 ++++++++++++++ .../pull-req-stats/pull-req-stats.html | 1 + .../pull-req-stats/pull-req-stats.module.js | 29 ++++++++++++++ .../pull-req-stats/pull-req-stats.spec.js | 40 +++++++++++++++++++ .../repo-details/repo-details.component.js | 14 +++++-- .../repo-details/repo-details.module.js | 8 ---- .../src/components/search/search.component.js | 20 +++++----- .../client/src/components/search/search.html | 2 +- .../src/components/search/search.spec.js | 16 ++++---- .../index/static/client/src/main.component.js | 3 ++ .../index/static/client/src/main.module.js | 17 +++++++- 12 files changed, 153 insertions(+), 32 deletions(-) create mode 100644 repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js create mode 100644 repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.html create mode 100644 repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js create mode 100644 repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js diff --git a/repo_health/index/static/client/src/components/components.module.js b/repo_health/index/static/client/src/components/components.module.js index b82e76a..faa6c9e 100644 --- a/repo_health/index/static/client/src/components/components.module.js +++ b/repo_health/index/static/client/src/components/components.module.js @@ -6,17 +6,20 @@ * * Author(s) of this file: * @bparish628 +* J.Harding * * This is the definitions for all of the components used in this application. */ import search from './search/search.module'; import repoDetails from './repo-details/repo-details.module'; +import pullReqStats from './pull-req-stats/pull-req-stats.module'; const components = angular .module('components', [ search, - repoDetails + repoDetails, + pullReqStats ]) .name; diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js new file mode 100644 index 0000000..423f892 --- /dev/null +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -0,0 +1,30 @@ +/* +* pull-req-stats.component.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* This is the creation of the pull-req-stats component. +*/ + +import template from './pull-req-stats'; + +const pullReqStatsComponent = { + template, + controller: class pullReqStatsComponent { + + constructor($state, $stateParams) { + 'ngInject'; + Object.assign(this, { $state, $stateParams }); + } + + $onInit() { + console.log(this.$stateParams); + } + } +}; + +export default pullReqStatsComponent; diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.html b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.html new file mode 100644 index 0000000..f92c38b --- /dev/null +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.html @@ -0,0 +1 @@ +

Hello stats

\ No newline at end of file diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js new file mode 100644 index 0000000..73d9b29 --- /dev/null +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js @@ -0,0 +1,29 @@ +/* +* pull-req-stats.module.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* This is the module definition for the repo-details component +*/ + +import uiRouter from 'angular-ui-router'; +import pullReqStatsComponent from './pull-req-stats.component'; + +const components = angular + .module('components.pull-req-stats', []) + // .service('PullReqStats', pullPreqStats) + .component('pullReqStats', pullReqStatsComponent) + // .run($api => { + // 'ngInject'; + // $api.add({ + // resource: 'repo', + // url: '/' + // }); + // }) + .name; + +export default components; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js new file mode 100644 index 0000000..a4e8f69 --- /dev/null +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js @@ -0,0 +1,40 @@ +/* +* pull-req-stats.spec.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* This is the test file for the search component +*/ + +const module = angular.mock.module; + +describe('Pull Req Stats', () => { + + beforeEach(module( + 'app.resources', + 'components.search', + 'components.repo-details', + 'components.pull-req-stats' + )); + + describe('PullReqStatsController', () => { + let $componentController; + let controller; + + beforeEach(inject(($injector) => { + $componentController = $injector.get('$componentController'); + controller = $componentController('pullReqStats'); + })); + + describe('constructor', () => { + it('should setup the controller', () => { + expect(controller).toBeDefined(); + }); + }); + + }); +}); \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index ce670d0..2e9fea4 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -19,13 +19,21 @@ const repoDetailsComponent = { loadingRepo = true; details = null; - constructor(RepoDetailsService, $state, $stateParams) { + constructor(RepoDetailsService, $state, $stateParams, $filter) { 'ngInject'; - Object.assign(this, { RepoDetailsService, $state, $stateParams }); + Object.assign(this, { RepoDetailsService, $state, $stateParams, $filter }); } $onInit() { - this.getStats(); + if (this.hasValidStateParams()) + this.getStats(); + } + + hasValidStateParams () { + let nulls = this.$filter('filter')(Object.keys(this.$stateParams), (key) => { + return !!this.$stateParams[key]; + }); + return nulls.length != 0; } getStats() { diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.module.js b/repo_health/index/static/client/src/components/repo-details/repo-details.module.js index 64d1f94..ed7679c 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.module.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.module.js @@ -18,14 +18,6 @@ const components = angular .module('components.repo-details', [uiRouter]) .service('RepoDetailsService', repoDetailsService) .component('repoDetails', repoDetailsComponent) - .config($stateProvider => { - 'ngInject'; - - $stateProvider.state('repo-details', { - url: '/repo-details?name&owner__login', - template: '' - }) - }) .run($api => { 'ngInject'; $api.add({ diff --git a/repo_health/index/static/client/src/components/search/search.component.js b/repo_health/index/static/client/src/components/search/search.component.js index 2bd1673..2c0db91 100644 --- a/repo_health/index/static/client/src/components/search/search.component.js +++ b/repo_health/index/static/client/src/components/search/search.component.js @@ -25,17 +25,15 @@ const searchComponent = { } getStats() { - const params = this.RepoDetailsService.getNameAndOwnerFromUrl(this.githubUrl); - if (params) { - this.loadingRepo = true - this.error = null; - this.RepoDetailsService.getStats(params).then(() => { - this.$state.go('repo-details', params); - }, () => { - this.error = 'This repo does not exist'; - this.loadingRepo = false; - }); - } + const params = this.RepoDetailsService.getNameAndOwnerFromUrl(this.githubUrl); + if (params) { + this.loadingRepo = true; + this.error = null; + this.$state.go('repo-report', params); + } else { + this.error = 'This repo does not exist'; + this.loadingRepo = false; + } } } }; diff --git a/repo_health/index/static/client/src/components/search/search.html b/repo_health/index/static/client/src/components/search/search.html index 7797e71..1dcc198 100644 --- a/repo_health/index/static/client/src/components/search/search.html +++ b/repo_health/index/static/client/src/components/search/search.html @@ -26,7 +26,7 @@

Github Url

- Get Statistics + Get Statistics
diff --git a/repo_health/index/static/client/src/components/search/search.spec.js b/repo_health/index/static/client/src/components/search/search.spec.js index b44064c..ba3f196 100644 --- a/repo_health/index/static/client/src/components/search/search.spec.js +++ b/repo_health/index/static/client/src/components/search/search.spec.js @@ -16,10 +16,12 @@ describe('Search', () => { let sandbox; beforeEach(module( - 'app.resources', + 'app.resources', + 'repo-health', 'components.repo-details', - 'components.search') - ); + 'components.pull-req-stats', + 'components.search' + )); describe('SearchController', () => { let $componentController; @@ -62,17 +64,17 @@ describe('Search', () => { controller.githubUrl = 'https://github.com/cakephp/cakephp'; controller.getStats(); expect(controller.loadingRepo).toBeTruthy(); - expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); + // expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); }); it('should set an error if it fails', () => { - spyOn(controller.RepoDetailsService, 'getStats').and.returnValue($q.reject('error')); - controller.githubUrl = 'https://github.com/cakephp/cakephp'; + // spyOn(controller.RepoDetailsService, 'getStats').and.returnValue($q.reject('error')); + controller.githubUrl = 'https://github.com/cakephp/'; controller.getStats(); $rootScope.$apply(); expect(controller.loadingRepo).toBeFalsy(); expect(controller.error).toEqual('This repo does not exist'); - expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); + // expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); }); }); }); diff --git a/repo_health/index/static/client/src/main.component.js b/repo_health/index/static/client/src/main.component.js index 579af90..d722836 100644 --- a/repo_health/index/static/client/src/main.component.js +++ b/repo_health/index/static/client/src/main.component.js @@ -16,6 +16,9 @@ const template = `
+
+
+
`; diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index fd57688..e61a863 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -28,11 +28,26 @@ export const main = angular.module('repo-health', [ resources ]) .component('main', mainComponent) - .config(($locationProvider, $urlRouterProvider, $mdThemingProvider) => { + .config(($locationProvider, $urlRouterProvider, $mdThemingProvider, $stateProvider) => { 'ngInject'; $locationProvider.hashPrefix(''); $urlRouterProvider.otherwise('/search'); + $stateProvider.state('repo-report', { + url: '/repo-report', + params: { + name: null, + owner__login: null + }, + views: { + 'repo-details': { + template: '' + }, + 'pull-req-stats': { + template: '' + } + } + }) // Set-up themes $mdThemingProvider.theme('error').backgroundPalette('red').dark(); From e77c00ad2c30b0596798e78fd806130b48df057d Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 19 Mar 2017 09:17:28 -0500 Subject: [PATCH 48/99] Make input required on search page. Use url params on repo health. --- .../src/components/search/search.component.js | 3 ++- .../client/src/components/search/search.html | 18 +++++++++++++++--- .../index/static/client/src/main.module.js | 10 +++------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/repo_health/index/static/client/src/components/search/search.component.js b/repo_health/index/static/client/src/components/search/search.component.js index 2c0db91..b412a49 100644 --- a/repo_health/index/static/client/src/components/search/search.component.js +++ b/repo_health/index/static/client/src/components/search/search.component.js @@ -18,6 +18,7 @@ const searchComponent = { loadingRepo = false; error = null; + githubUrlRegex = '^(?:https:\/\/)?(?:www\.)?(?:github\.com\/)?(.+[^https:\/\/])\/(.+)(\/)?$'; constructor(RepoDetailsService, $state, $stateParams) { 'ngInject'; @@ -29,7 +30,7 @@ const searchComponent = { if (params) { this.loadingRepo = true; this.error = null; - this.$state.go('repo-report', params); + this.$state.go('repo-health', params); } else { this.error = 'This repo does not exist'; this.loadingRepo = false; diff --git a/repo_health/index/static/client/src/components/search/search.html b/repo_health/index/static/client/src/components/search/search.html index 1dcc198..0fd2aa4 100644 --- a/repo_health/index/static/client/src/components/search/search.html +++ b/repo_health/index/static/client/src/components/search/search.html @@ -22,11 +22,23 @@

Github Url

- - + +
- Get Statistics + + Get Statistics +
diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index e61a863..5fb80a0 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -33,12 +33,8 @@ export const main = angular.module('repo-health', [ $locationProvider.hashPrefix(''); $urlRouterProvider.otherwise('/search'); - $stateProvider.state('repo-report', { - url: '/repo-report', - params: { - name: null, - owner__login: null - }, + $stateProvider.state('repo-health', { + url: '/repo-health/:owner__login/:name', views: { 'repo-details': { template: '' @@ -53,7 +49,7 @@ export const main = angular.module('repo-health', [ $mdThemingProvider.theme('error').backgroundPalette('red').dark(); $mdThemingProvider.theme('default') - .primaryPalette('light-blue') + .primaryPalette('blue') .accentPalette('orange') .backgroundPalette('blue-grey'); }) From ec558302fee9681aa35f5560c921499c28ccaa7f Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 19 Mar 2017 10:46:07 -0500 Subject: [PATCH 49/99] Added metrics django module. Request repo details everytime in RepoDetailsService to prevent details being displayed for wrong repo. --- docs/rest_api/Response.md | 46 +++++++++++++++++++ .../pull-req-stats.component.js | 11 +++-- .../pull-req-stats/pull-req-stats.module.js | 14 +++--- .../repo-details/repo-details.service.js | 16 +++---- .../src/components/search/search.component.js | 13 +++--- repo_health/metrics/__init__.py | 0 repo_health/metrics/admin.py | 3 ++ repo_health/metrics/apps.py | 5 ++ repo_health/metrics/migrations/__init__.py | 0 repo_health/metrics/models.py | 3 ++ .../metrics/serializers/ResponseSerializer.py | 26 +++++++++++ repo_health/metrics/serializers/__init__.py | 0 repo_health/metrics/tests.py | 3 ++ repo_health/metrics/views.py | 3 ++ 14 files changed, 118 insertions(+), 25 deletions(-) create mode 100644 docs/rest_api/Response.md create mode 100644 repo_health/metrics/__init__.py create mode 100644 repo_health/metrics/admin.py create mode 100644 repo_health/metrics/apps.py create mode 100644 repo_health/metrics/migrations/__init__.py create mode 100644 repo_health/metrics/models.py create mode 100644 repo_health/metrics/serializers/ResponseSerializer.py create mode 100644 repo_health/metrics/serializers/__init__.py create mode 100644 repo_health/metrics/tests.py create mode 100644 repo_health/metrics/views.py diff --git a/docs/rest_api/Response.md b/docs/rest_api/Response.md new file mode 100644 index 0000000..7596e43 --- /dev/null +++ b/docs/rest_api/Response.md @@ -0,0 +1,46 @@ +# REST API response schema + +Represents a response schema for a request to the API. A list of metrics are returned to allow + the client to iterate over the response and build the UI based on what the API provides. + + Comments are added for clarification. + + ``` + [ + { + display: string, //display name of the metric + ordering: int, //order if the metric in UI + metric: int | [int] | string, //Actual data. Array of ints if it is a chart + chart_type: null | string, //Type of chart if chart is used + chart_name: null | stirng, //Name of chart to allow multiple metrics on one chart + + }, + ... + ] + ``` + ## OR + +``` +{ + ...//Maybe some other data defining the Response to the UI + charts: { + chart_name : { + chart_type: int, //Enumerate chart types? + x_names: [string], + y_names: [string] + }, + ... + }, + metrics: [ + { + is_displayed: bool, //Should the metric be displayed in the UI + display_name: string, //display name of the metric + ordering: int, //order of the metric in UI. Order of chart is metric is in chart + metric: int | [int] | string | bool, //Actual data. Array of ints if it is a chart + chart_name: null | string, //Name of chart to allow multiple metrics on one chart + + }, +... + ] + } + ``` \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index 423f892..1147f6f 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -15,14 +15,17 @@ import template from './pull-req-stats'; const pullReqStatsComponent = { template, controller: class pullReqStatsComponent { - - constructor($state, $stateParams) { + stats = null; + constructor(RepoDetailsService, $state, $stateParams, $repo) { 'ngInject'; - Object.assign(this, { $state, $stateParams }); + Object.assign(this, { RepoDetailsService, $state, $stateParams, $repo }); } $onInit() { - console.log(this.$stateParams); + console.log(this.RepoDetailsService.repoDetails); + // this.$repo.get('pullReqStats').then(stats => { + // this.stats = stats; + // }); } } }; diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js index 73d9b29..a0d7bba 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js @@ -17,13 +17,13 @@ const components = angular .module('components.pull-req-stats', []) // .service('PullReqStats', pullPreqStats) .component('pullReqStats', pullReqStatsComponent) - // .run($api => { - // 'ngInject'; - // $api.add({ - // resource: 'repo', - // url: '/' - // }); - // }) + .run($api => { + 'ngInject'; + $api.add({ + resource: 'pullReqStats', + url: '/pull-requests' + }); + }) .name; export default components; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js index e3c01b2..b81fdb3 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js @@ -22,9 +22,9 @@ class RepoDetailsService { /* Gets the last two strings on a url */ getNameAndOwnerFromUrl(url = '') { - if (url.search('github.com') == -1) { - return; - } + // if (url.search('github.com') == -1) { + // return; + // } const pathArray = url.replace(/.*github.com\//, '').split('/'); const name = pathArray.pop(); @@ -33,11 +33,11 @@ class RepoDetailsService { } getStats(params) { - if (this.repoDetails) { - return this.$q.resolve(this.repoDetails); - } else { - return this.$repo.get('repo', params).then(details => (this.repoDetails = details)); - } + // if (this.repoDetails) { + // return this.$q.resolve(this.repoDetails); + // } else { + return this.$repo.get('repo', params).then(details => (this.repoDetails = details)); + // } } } diff --git a/repo_health/index/static/client/src/components/search/search.component.js b/repo_health/index/static/client/src/components/search/search.component.js index b412a49..c9f2f29 100644 --- a/repo_health/index/static/client/src/components/search/search.component.js +++ b/repo_health/index/static/client/src/components/search/search.component.js @@ -18,7 +18,6 @@ const searchComponent = { loadingRepo = false; error = null; - githubUrlRegex = '^(?:https:\/\/)?(?:www\.)?(?:github\.com\/)?(.+[^https:\/\/])\/(.+)(\/)?$'; constructor(RepoDetailsService, $state, $stateParams) { 'ngInject'; @@ -27,13 +26,15 @@ const searchComponent = { getStats() { const params = this.RepoDetailsService.getNameAndOwnerFromUrl(this.githubUrl); - if (params) { + if (params && params.owner__login != this.$stateParams.owner__login) { this.loadingRepo = true; this.error = null; - this.$state.go('repo-health', params); - } else { - this.error = 'This repo does not exist'; - this.loadingRepo = false; + this.RepoDetailsService.getStats(params).then(() => { + this.$state.go('repo-health', params); + }, () => { + this.error = 'This repo does not exist'; + this.loadingRepo = false; + }); } } } diff --git a/repo_health/metrics/__init__.py b/repo_health/metrics/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/repo_health/metrics/admin.py b/repo_health/metrics/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/repo_health/metrics/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/repo_health/metrics/apps.py b/repo_health/metrics/apps.py new file mode 100644 index 0000000..1e777e4 --- /dev/null +++ b/repo_health/metrics/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class MetricsConfig(AppConfig): + name = 'metrics' diff --git a/repo_health/metrics/migrations/__init__.py b/repo_health/metrics/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/repo_health/metrics/models.py b/repo_health/metrics/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/repo_health/metrics/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/repo_health/metrics/serializers/ResponseSerializer.py b/repo_health/metrics/serializers/ResponseSerializer.py new file mode 100644 index 0000000..bc202b7 --- /dev/null +++ b/repo_health/metrics/serializers/ResponseSerializer.py @@ -0,0 +1,26 @@ +""" +ResponseSerializers.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Serializers for api response. +""" + + +from rest_framework import serializers as s + + +class ResponseSerializer(s.Serializer): + + charts = s.SerializerMethodField() + metrics = s.SerializerMethodField() + + def get_charts(self, obj): + return [] + + def get_metrics(self, obj): + return [] \ No newline at end of file diff --git a/repo_health/metrics/serializers/__init__.py b/repo_health/metrics/serializers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/repo_health/metrics/tests.py b/repo_health/metrics/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/repo_health/metrics/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/repo_health/metrics/views.py b/repo_health/metrics/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/repo_health/metrics/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From bffbdf525566fa12e23779e2808556a00a231b96 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 19 Mar 2017 10:56:46 -0500 Subject: [PATCH 50/99] Making pr stats request. --- .../pull-req-stats/pull-req-stats.component.js | 14 +++++++++++--- .../pull-req-stats/pull-req-stats.module.js | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index 1147f6f..50a06b1 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -16,6 +16,8 @@ const pullReqStatsComponent = { template, controller: class pullReqStatsComponent { stats = null; + loadingStats = true; + loadingMsg = "Loading issue stats..." constructor(RepoDetailsService, $state, $stateParams, $repo) { 'ngInject'; Object.assign(this, { RepoDetailsService, $state, $stateParams, $repo }); @@ -23,9 +25,15 @@ const pullReqStatsComponent = { $onInit() { console.log(this.RepoDetailsService.repoDetails); - // this.$repo.get('pullReqStats').then(stats => { - // this.stats = stats; - // }); + if(this.RepoDetailsService.repoDetails) { + let params = { + id: this.RepoDetailsService.repoDetails.id, + verb: 'pull-requests' + } + this.$repo.get('pullReqStats', params).then(stats => { + this.stats = stats; + }); + } } } }; diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js index a0d7bba..47bc8b9 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js @@ -21,7 +21,7 @@ const components = angular 'ngInject'; $api.add({ resource: 'pullReqStats', - url: '/pull-requests' + url: '' }); }) .name; From 6ff9487565cdd328adb330b3800563e8af7014a2 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 20 Mar 2017 16:37:48 -0500 Subject: [PATCH 51/99] Switch search api to return urls. --- .../serializers/StatsUrlSerializer.py | 32 +++++++++++++++++++ .../gh_projects/serializers/__init__.py | 1 + repo_health/gh_projects/tests.py | 1 + repo_health/gh_projects/views.py | 15 ++++++--- repo_health/rest_api/__init__.py | 2 +- 5 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 repo_health/gh_projects/serializers/StatsUrlSerializer.py diff --git a/repo_health/gh_projects/serializers/StatsUrlSerializer.py b/repo_health/gh_projects/serializers/StatsUrlSerializer.py new file mode 100644 index 0000000..44af90c --- /dev/null +++ b/repo_health/gh_projects/serializers/StatsUrlSerializer.py @@ -0,0 +1,32 @@ +""" +StatsUrlSerializer.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Serializer for urls to retrieve stats about a GitHub repo. +""" + +from rest_framework.serializers import Serializer, SerializerMethodField +from rest_framework.reverse import reverse + +class StatsUrlsSerializer(Serializer): + + repo_details_url = SerializerMethodField() + # issue_stats_url = SerializerMethodField() + pr_stats_url = SerializerMethodField() + + def get_repo_details_url(self, repo): + return self.get_stats_url('gh-project-detail', repo.id) + + def get_issue_stats_url(self, repo): + return self.get_stats_url('gh-project-issues', repo.id) + + def get_pr_stats_url(self, repo): + return self.get_stats_url('gh-project-pull-requests', repo.id) + + def get_stats_url(self, url_name, repo_id): + return reverse(url_name, args=[repo_id], request=self.context.get('request')) \ No newline at end of file diff --git a/repo_health/gh_projects/serializers/__init__.py b/repo_health/gh_projects/serializers/__init__.py index fd324d0..f7af616 100644 --- a/repo_health/gh_projects/serializers/__init__.py +++ b/repo_health/gh_projects/serializers/__init__.py @@ -11,3 +11,4 @@ """ from .GhProjectSerializer import GhProjectSerializer +from .StatsUrlSerializer import StatsUrlsSerializer diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index b38afd5..72936fb 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -69,6 +69,7 @@ def setUp(self): def test_api_get_project(self): r = self.client.get('/api/v1/gh-projects', {'owner__login':self.project.owner.login, 'name':self.project.name}) self.assertTrue(status.is_success(r.status_code)) + import pprint as pp; pp.pprint(r.data) self.assertEqual(r.data['name'], self.project.name) self.assertEqual(r.data['id'], self.project.id) diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index 6b924f3..591bcf4 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -12,7 +12,7 @@ from django.db import models -from rest_framework.mixins import ListModelMixin +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.viewsets import GenericViewSet from rest_framework.exceptions import NotFound from rest_framework.status import HTTP_404_NOT_FOUND @@ -20,15 +20,22 @@ from rest_framework.decorators import detail_route from repo_health.gh_pull_requests.serializers import GhPullRequestStatsSerializer from .models import GhProject -from .serializers import GhProjectSerializer +from .serializers import GhProjectSerializer, StatsUrlsSerializer -class GhProjectViewSet(ListModelMixin, GenericViewSet): +class GhProjectViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): queryset = GhProject.objects.all() - serializer_class = GhProjectSerializer + serializer_class = StatsUrlsSerializer filter_fields = ('owner__login', 'name') def list(self, r, *args, **kwargs): + """ + Temporary override as we may use this method to filter repos for an autocomplete. + :param r: Request for repo + :param args: + :param kwargs: + :return: Response + """ if not r.GET.get('name') or not r.GET.get('owner__login'): raise NotFound('Repo not found', HTTP_404_NOT_FOUND) response = super().list(r, *args, **kwargs) diff --git a/repo_health/rest_api/__init__.py b/repo_health/rest_api/__init__.py index b31494c..39ffcf7 100644 --- a/repo_health/rest_api/__init__.py +++ b/repo_health/rest_api/__init__.py @@ -15,7 +15,7 @@ from repo_health.gh_projects.views import GhProjectViewSet router = routers.DefaultRouter(trailing_slash=False) -router.register('gh-projects', GhProjectViewSet) +router.register('gh-projects', GhProjectViewSet, base_name='gh-project') urlpatterns = [ url(r'^', include(router.urls)), From 35f0e6421b60f4dfad5b911cf0dbd8bcfe1d484b Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 20 Mar 2017 17:25:26 -0500 Subject: [PATCH 52/99] Switch to project serializer in backend when making request with id. --- .../serializers/GhProjectSerializer.py | 2 +- repo_health/gh_projects/tests.py | 21 ++++++++++++++----- repo_health/gh_projects/views.py | 12 +++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/repo_health/gh_projects/serializers/GhProjectSerializer.py b/repo_health/gh_projects/serializers/GhProjectSerializer.py index 0268782..436c99b 100644 --- a/repo_health/gh_projects/serializers/GhProjectSerializer.py +++ b/repo_health/gh_projects/serializers/GhProjectSerializer.py @@ -38,7 +38,7 @@ def __init__(self, *args, **kwargs): Get some statistics for repo. """ super().__init__(*args, **kwargs) - repo = args[0].first() + repo = args[0] if repo is not None: commits = (repo.commits_m2m.all() | repo.commits_fk.all()).order_by('-created_at') commit_users = GhUser.objects.filter(authored_commits__in=commits).distinct() diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 72936fb..577a2fb 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -14,8 +14,10 @@ import datetime from django.test import TestCase, Client from django.db import models as m +from django.shortcuts import reverse as dj_reverse from rest_framework import status from rest_framework.test import APITestCase +from rest_framework.reverse import reverse from .models import GhProject, GhRepoLabel @@ -67,15 +69,24 @@ def setUp(self): self.django = GhProject.objects.get(name='django', owner__login='django') def test_api_get_project(self): - r = self.client.get('/api/v1/gh-projects', {'owner__login':self.project.owner.login, 'name':self.project.name}) + r = self.client.get(dj_reverse('gh-project-detail', args=[self.project.id])) self.assertTrue(status.is_success(r.status_code)) - import pprint as pp; pp.pprint(r.data) - self.assertEqual(r.data['name'], self.project.name) - self.assertEqual(r.data['id'], self.project.id) + self.assertEqual(r.data.get('id'), self.project.id) + + #test with bad input + max_id = GhProject.objects.all().aggregate(m.Max('id')).get('id__max') + bad_input = self.client.get(dj_reverse('gh-project-detail', args=[max_id + 1])) + self.assertTrue(status.is_client_error(bad_input.status_code)) + + def test_api_get_repo_stats_urls(self): + r = self.client.get('/api/v1/gh-projects', {'owner__login': self.project.owner.login, 'name': self.project.name}) + self.assertTrue(status.is_success(r.status_code)) + self.assertEqual(r.data['repo_details_url'], reverse('gh-project-detail', args=[self.project.id], request=r.wsgi_request)) + self.assertEqual(r.data['pr_stats_url'], reverse('gh-project-pull-requests', args=[self.project.id], request=r.wsgi_request)) def test_api_get_project_not_found(self): # Test with a bad owner login - r_with_bad_owner = self.client.get('/api/v1/gh-projects', {'owner__login':'incoherehnet giibbuusrish', 'name':self.project.name}) + r_with_bad_owner = self.client.get('/api/v1/gh-projects', {'owner__login':'incoherehnet giibbuusrish', 'name': self.project.name}) self.assertTrue(status.is_client_error(r_with_bad_owner.status_code)) # Test with a bad repo name diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index 591bcf4..6322be0 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -28,6 +28,18 @@ class GhProjectViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): serializer_class = StatsUrlsSerializer filter_fields = ('owner__login', 'name') + def retrieve(self, r, *args, **kwargs): + """ + Override to use the correct serializer. Otherwise it would use the stats serializer. + get_object method returns a 404 if project is not found. + :param r: Request object + :param args: pk of project is the first arg + :param kwargs: + :return: Response + """ + obj = self.get_object() + return Response(GhProjectSerializer(obj).data) + def list(self, r, *args, **kwargs): """ Temporary override as we may use this method to filter repos for an autocomplete. From 632385e40eb2418dab5267d2eccb7e7e0af0563b Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 20 Mar 2017 19:25:26 -0500 Subject: [PATCH 53/99] Move front end to using urls from subsequent requests. --- .../base-component/base.template.html | 35 ++++++++++++ .../pull-req-stats.component.js | 32 ++++++----- .../pull-req-stats/pull-req-stats.html | 1 - .../pull-req-stats/pull-req-stats.module.js | 17 +++--- .../repo-details/repo-details.component.js | 30 ++++------- .../components/repo-details/repo-details.html | 53 ++++++++++--------- .../repo-details/repo-details.module.js | 2 +- .../repo-details/repo-details.service.js | 4 +- .../repo-details/repo-details.spec.js | 10 ++-- .../src/components/search/search.component.js | 11 ++-- .../client/src/components/search/search.html | 11 ++-- .../src/components/search/search.spec.js | 18 +++---- .../index/static/client/src/main.module.js | 37 ++++++++++++- 13 files changed, 160 insertions(+), 101 deletions(-) create mode 100644 repo_health/index/static/client/src/components/base-component/base.template.html delete mode 100644 repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.html diff --git a/repo_health/index/static/client/src/components/base-component/base.template.html b/repo_health/index/static/client/src/components/base-component/base.template.html new file mode 100644 index 0000000..4c025bc --- /dev/null +++ b/repo_health/index/static/client/src/components/base-component/base.template.html @@ -0,0 +1,35 @@ + + + +
+ {{::$ctrl.loadingMsg}} +
+ +
+
+
+ + + {{::$ctrl.stats.name}} + {{::$ctrl.stats.description}} + + + +
+
Language: {{$ctrl.stats.language}}
+
Contributions: {{$ctrl.stats.contribs_count}}
+
+ +
+
Watchers: {{$ctrl.stats.watchers_count}}
+
Commits: {{$ctrl.stats.commits_count}}
+
+ +
+
Milestones: {{$ctrl.stats.milestones_count}}
+
Forks: {{$ctrl.stats.forks_count}}
+
+
+
+
+
diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index 50a06b1..3d241df 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -10,30 +10,36 @@ * This is the creation of the pull-req-stats component. */ -import template from './pull-req-stats'; +import template from '../base-component/base.template'; const pullReqStatsComponent = { template, + bindings: {prStatsUrl: '='}, controller: class pullReqStatsComponent { stats = null; loadingStats = true; loadingMsg = "Loading issue stats..." - constructor(RepoDetailsService, $state, $stateParams, $repo) { + constructor(RepoDetailsService, $state, $stateParams, $http) { 'ngInject'; - Object.assign(this, { RepoDetailsService, $state, $stateParams, $repo }); + Object.assign(this, { RepoDetailsService, $state, $stateParams, $http }); } $onInit() { - console.log(this.RepoDetailsService.repoDetails); - if(this.RepoDetailsService.repoDetails) { - let params = { - id: this.RepoDetailsService.repoDetails.id, - verb: 'pull-requests' - } - this.$repo.get('pullReqStats', params).then(stats => { - this.stats = stats; - }); - } + this.$http.get(this.prStatsUrl).then(stats => { + this.stats = stats.data; + this.loadingStats = false; + }) + // this.RepoDetailsService.getStats(this.$stateParams).then( () => { + // let params = { + // id: this.RepoDetailsService.repoDetails.id, + // verb: 'pull-requests' + // } + // this.$repo.get('pullReqStats', params).then(stats => { + // this.stats = stats; + // this.loadingStats = false; + // }, () => {this.$state.go('search')} + // ); + // }); } } }; diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.html b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.html deleted file mode 100644 index f92c38b..0000000 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.html +++ /dev/null @@ -1 +0,0 @@ -

Hello stats

\ No newline at end of file diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js index 47bc8b9..5396ef6 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js @@ -7,7 +7,7 @@ * Author(s) of this file: * J.Harding * -* This is the module definition for the repo-details component +* This is the module definition for the pr stats module */ import uiRouter from 'angular-ui-router'; @@ -15,15 +15,14 @@ import pullReqStatsComponent from './pull-req-stats.component'; const components = angular .module('components.pull-req-stats', []) - // .service('PullReqStats', pullPreqStats) .component('pullReqStats', pullReqStatsComponent) - .run($api => { - 'ngInject'; - $api.add({ - resource: 'pullReqStats', - url: '' - }); - }) + // .run($api => { + // 'ngInject'; + // $api.add({ + // resource: 'pullReqStats', + // url: '' + // }); + // }) .name; export default components; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index 2e9fea4..96c15fa 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -10,37 +10,27 @@ * This is the creation of the search component. */ -import template from './repo-details'; +import template from '../base-component/base.template'; +// import template from './repo-details'; const repoDetailsComponent = { template, + bindings: {detailsUrl: '='}, controller: class repoDetailsComponent { - loadingRepo = true; - details = null; + loadingStats = true; + loadingMsg = "Loading general repo stats..." - constructor(RepoDetailsService, $state, $stateParams, $filter) { + constructor($http) { 'ngInject'; - Object.assign(this, { RepoDetailsService, $state, $stateParams, $filter }); + Object.assign(this, { $http }); } $onInit() { - if (this.hasValidStateParams()) - this.getStats(); - } - - hasValidStateParams () { - let nulls = this.$filter('filter')(Object.keys(this.$stateParams), (key) => { - return !!this.$stateParams[key]; + this.$http.get(this.detailsUrl).then(details => { + this.stats = details.data; + this.loadingStats = false; }); - return nulls.length != 0; - } - - getStats() { - this.RepoDetailsService.getStats(this.$stateParams).then(details => { - this.loadingRepo = false; - this.details = details; - }, () => this.$state.go('search')); } } }; diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.html b/repo_health/index/static/client/src/components/repo-details/repo-details.html index 8ea2d1c..75a4cdf 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.html +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.html @@ -1,32 +1,35 @@ -
- Loading your repository... Please wait... -
- -
-
- + + - - - {{::$ctrl.details.name}} - {{::$ctrl.details.description}} - - - -
-
Language: {{$ctrl.details.language}}
-
Contributions: {{$ctrl.details.contribs_count}}
+
+ Loading your repository... Please wait... +
+ +
+
+ + + {{::$ctrl.details.name}} + {{::$ctrl.details.description}} + + + +
+
Language: {{$ctrl.details.language}}
+
Contributions: {{$ctrl.details.contribs_count}}
+
-
-
Watchers: {{$ctrl.details.watchers_count}}
-
Commits: {{$ctrl.details.commits_count}}
-
+
+
Watchers: {{$ctrl.details.watchers_count}}
+
Commits: {{$ctrl.details.commits_count}}
+
-
-
Milestones: {{$ctrl.details.milestones_count}}
-
Forks: {{$ctrl.details.forks_count}}
+
+
Milestones: {{$ctrl.details.milestones_count}}
+
Forks: {{$ctrl.details.forks_count}}
+
+
-
diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.module.js b/repo_health/index/static/client/src/components/repo-details/repo-details.module.js index ed7679c..be878c3 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.module.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.module.js @@ -21,7 +21,7 @@ const components = angular .run($api => { 'ngInject'; $api.add({ - resource: 'repo', + resource: 'repoStatsUrls', url: '/' }); }) diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js index b81fdb3..7743a2d 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js @@ -32,11 +32,11 @@ class RepoDetailsService { return name && owner__login ? { owner__login, name } : undefined; } - getStats(params) { + getStatsUrls(params) { // if (this.repoDetails) { // return this.$q.resolve(this.repoDetails); // } else { - return this.$repo.get('repo', params).then(details => (this.repoDetails = details)); + return this.$repo.get('repoStatsUrls', params).then(details => (this.repoDetails = details)); // } } diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index e725501..5267c34 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -50,11 +50,11 @@ describe('Repo Details', () => { }); }); - describe('getStats', () => { + describe('getStatsUrls', () => { it('should make a call to service', () => { - spyOn(controller.RepoDetailsService, 'getStats').and.returnValue($q.resolve({ name: 'cakephp' })); - expect(controller.RepoDetailsService.getStats).not.toHaveBeenCalled(); - controller.getStats(); + spyOn(controller.RepoDetailsService, 'getStatsUrls').and.returnValue($q.resolve({ name: 'cakephp' })); + expect(controller.RepoDetailsService.getStatsUrls).not.toHaveBeenCalled(); + controller.getStatsUrls(); $rootScope.$apply(); expect(controller.loadingRepo).toBeFalsy(); expect(controller.details).toEqual({ name: 'cakephp' }); @@ -88,7 +88,7 @@ describe('Repo Details', () => { }); }); - describe('getStats', () => { + describe('getStatsUrls', () => { it('should return a promise if repoDetails exists', () => { RepoDetailsService.repoDetails = { name: 'cakephp', watchers: 123 }; RepoDetailsService.getStats().then(details => { diff --git a/repo_health/index/static/client/src/components/search/search.component.js b/repo_health/index/static/client/src/components/search/search.component.js index c9f2f29..7272342 100644 --- a/repo_health/index/static/client/src/components/search/search.component.js +++ b/repo_health/index/static/client/src/components/search/search.component.js @@ -24,20 +24,19 @@ const searchComponent = { Object.assign(this, { RepoDetailsService, $state, $stateParams }); } - getStats() { + getStatsUrls() { const params = this.RepoDetailsService.getNameAndOwnerFromUrl(this.githubUrl); - if (params && params.owner__login != this.$stateParams.owner__login) { + if (params) { this.loadingRepo = true; this.error = null; - this.RepoDetailsService.getStats(params).then(() => { + // this.RepoDetailsService.getStats(params).then(() => { this.$state.go('repo-health', params); - }, () => { + } else { this.error = 'This repo does not exist'; this.loadingRepo = false; - }); + }; } } - } }; export default searchComponent; diff --git a/repo_health/index/static/client/src/components/search/search.html b/repo_health/index/static/client/src/components/search/search.html index 0fd2aa4..4cff333 100644 --- a/repo_health/index/static/client/src/components/search/search.html +++ b/repo_health/index/static/client/src/components/search/search.html @@ -11,14 +11,9 @@
-
- Loading your repository... Please wait... -
- -
-
-
+ +

Github Url

@@ -34,7 +29,7 @@

Github Url

Get Statistics diff --git a/repo_health/index/static/client/src/components/search/search.spec.js b/repo_health/index/static/client/src/components/search/search.spec.js index ba3f196..5d45f8d 100644 --- a/repo_health/index/static/client/src/components/search/search.spec.js +++ b/repo_health/index/static/client/src/components/search/search.spec.js @@ -48,33 +48,33 @@ describe('Search', () => { }); }); - describe('getStats', () => { + describe('getStatsUrls', () => { let getStats; it('should not make a call if url is invalid', () => { spyOn(controller.RepoDetailsService, 'getStats'); controller.githubUrl = 'This not a url'; - controller.getStats(); - expect(controller.loadingRepo).toBeTrue; + controller.getStatsUrls(); + expect(controller.loadingRepo).toBeTruthy(); expect(controller.RepoDetailsService.getStats).not.toHaveBeenCalled(); }); - it('should make a call to getStats on the service', () => { + it('should make a call to getStatsUrls on the service', () => { spyOn(controller.RepoDetailsService, 'getStats').and.returnValue($q.resolve({ name: 'cakephp' })); controller.githubUrl = 'https://github.com/cakephp/cakephp'; - controller.getStats(); + controller.getStatsUrls(); expect(controller.loadingRepo).toBeTruthy(); - // expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); + // expect(controller.RepoDetailsService.getStatsUrls).toHaveBeenCalled(); }); it('should set an error if it fails', () => { - // spyOn(controller.RepoDetailsService, 'getStats').and.returnValue($q.reject('error')); + // spyOn(controller.RepoDetailsService, 'getStatsUrls').and.returnValue($q.reject('error')); controller.githubUrl = 'https://github.com/cakephp/'; - controller.getStats(); + controller.getStatsUrls(); $rootScope.$apply(); expect(controller.loadingRepo).toBeFalsy(); expect(controller.error).toEqual('This repo does not exist'); - // expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); + // expect(controller.RepoDetailsService.getStatsUrls).toHaveBeenCalled(); }); }); }); diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index 5fb80a0..b072eee 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -35,12 +35,45 @@ export const main = angular.module('repo-health', [ $urlRouterProvider.otherwise('/search'); $stateProvider.state('repo-health', { url: '/repo-health/:owner__login/:name', + // controller: class RepoHealthController { + // constructor(details) { + // this.details = details; + // } + // }, + // controllerAs: '$ctrl', + resolve: { + statsUrls: (RepoDetailsService, $stateParams) => { + return RepoDetailsService.getStatsUrls($stateParams); + } + }, views: { 'repo-details': { - template: '' + controller: class DetailsController { + constructor(detailsUrl) { + this.detailsUrl = detailsUrl; + } + }, + resolve: { + detailsUrl: (statsUrls) => { + return statsUrls["repo_details_url"]; + } + }, + controllerAs: '$ctrl', + template: '', }, 'pull-req-stats': { - template: '' + controller: class PrStatUrl { + constructor(prStatsUrl) { + this.prStatsUrl = prStatsUrl; + } + }, + controllerAs: '$ctrl', + resolve: { + prStatsUrl: (statsUrls) => { + return statsUrls['pr_stats_url']; + } + }, + template: '' } } }) From cc7ebc056bbc3a7c8300df42def9eda016efe25f Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 20 Mar 2017 21:44:40 -0500 Subject: [PATCH 54/99] Show error of response to get urls is a not found error. --- .../base-component/base-stats.controller.js | 23 +++++++++++++++++++ .../base-component/base.template.html | 5 ++++ .../pull-req-stats.component.js | 4 ++-- .../pull-req-stats/pull-req-stats.module.js | 7 ------ .../repo-details/repo-details.component.js | 1 - .../repo-details/repo-details.controller.js | 23 +++++++++++++++++++ .../repo-details/repo-details.service.js | 6 +---- .../repo-details/repo-details.spec.js | 14 +++++------ .../src/components/search/search.component.js | 14 +++++------ .../client/src/components/search/search.html | 2 +- .../src/components/search/search.module.js | 3 ++- .../index/static/client/src/main.module.js | 22 +++++------------- 12 files changed, 76 insertions(+), 48 deletions(-) create mode 100644 repo_health/index/static/client/src/components/base-component/base-stats.controller.js create mode 100644 repo_health/index/static/client/src/components/repo-details/repo-details.controller.js diff --git a/repo_health/index/static/client/src/components/base-component/base-stats.controller.js b/repo_health/index/static/client/src/components/base-component/base-stats.controller.js new file mode 100644 index 0000000..a78d440 --- /dev/null +++ b/repo_health/index/static/client/src/components/base-component/base-stats.controller.js @@ -0,0 +1,23 @@ +/* +* base-stats.controller.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* Base stats controller to handle an error state if no repos are return for an owner login and name request +*/ + + +export default class BaseStatsController { + + constructor ($state, Urls) { + if (!Urls) { + $state.go('search', {error:true}); + } + } + + +} diff --git a/repo_health/index/static/client/src/components/base-component/base.template.html b/repo_health/index/static/client/src/components/base-component/base.template.html index 4c025bc..00082f2 100644 --- a/repo_health/index/static/client/src/components/base-component/base.template.html +++ b/repo_health/index/static/client/src/components/base-component/base.template.html @@ -29,6 +29,11 @@
Milestones: {{$ctrl.stats.milestones_count}}
Forks: {{$ctrl.stats.forks_count}}
+ +
+
Pull Req: {{$ctrl.stats.prs_last_year}}
+
+
diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index 3d241df..dd6f0e8 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -19,9 +19,9 @@ const pullReqStatsComponent = { stats = null; loadingStats = true; loadingMsg = "Loading issue stats..." - constructor(RepoDetailsService, $state, $stateParams, $http) { + constructor( $http) { 'ngInject'; - Object.assign(this, { RepoDetailsService, $state, $stateParams, $http }); + Object.assign(this, { $http }); } $onInit() { diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js index 5396ef6..f6e6d4f 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js @@ -16,13 +16,6 @@ import pullReqStatsComponent from './pull-req-stats.component'; const components = angular .module('components.pull-req-stats', []) .component('pullReqStats', pullReqStatsComponent) - // .run($api => { - // 'ngInject'; - // $api.add({ - // resource: 'pullReqStats', - // url: '' - // }); - // }) .name; export default components; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index 96c15fa..03da839 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -11,7 +11,6 @@ */ import template from '../base-component/base.template'; -// import template from './repo-details'; const repoDetailsComponent = { template, diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.controller.js b/repo_health/index/static/client/src/components/repo-details/repo-details.controller.js new file mode 100644 index 0000000..7692834 --- /dev/null +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.controller.js @@ -0,0 +1,23 @@ +/* +*repo-details.controller.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* Extend base stats controller to handle error state. +* Adds the ability to inject the specific resolve of the details url. +* +*/ + +import BaseStatsController from '../base-component/base-stats.controller'; + +export default class RepoDetailsController extends BaseStatsController { + + constructor ($state, detailsUrl) { + super($state, detailsUrl); + Object.assign(this, {$state, detailsUrl}); + } +} \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js index 7743a2d..9a77d91 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js @@ -33,11 +33,7 @@ class RepoDetailsService { } getStatsUrls(params) { - // if (this.repoDetails) { - // return this.$q.resolve(this.repoDetails); - // } else { - return this.$repo.get('repoStatsUrls', params).then(details => (this.repoDetails = details)); - // } + return this.$repo.get('repoStatsUrls', params); } } diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index 5267c34..5c62a07 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -39,15 +39,15 @@ describe('Repo Details', () => { }); it('should setup loadingRepo and details', () => { - expect(controller.loadingRepo).toBeTruthy(); - expect(controller.details).toBeNull(); + expect(controller.loadingStats).toBeTruthy(); + expect(controller.stats).toBeNull(); }); - it('should setup RepoDetailsService, $state, $stateParams', () => { - expect(controller.RepoDetailsService).toBeDefined(); - expect(controller.$state).toBeDefined(); - expect(controller.$stateParams).toBeDefined(); - }); + // it('should setup RepoDetailsService, $state, $stateParams', () => { + // expect(controller.RepoDetailsService).toBeDefined(); + // expect(controller.$state).toBeDefined(); + // expect(controller.$stateParams).toBeDefined(); + // }); }); describe('getStatsUrls', () => { diff --git a/repo_health/index/static/client/src/components/search/search.component.js b/repo_health/index/static/client/src/components/search/search.component.js index 7272342..bc3fc7b 100644 --- a/repo_health/index/static/client/src/components/search/search.component.js +++ b/repo_health/index/static/client/src/components/search/search.component.js @@ -16,27 +16,25 @@ const searchComponent = { template, controller: class searchComponent { - loadingRepo = false; error = null; + errorMsg = 'This repo does not exist'; constructor(RepoDetailsService, $state, $stateParams) { 'ngInject'; Object.assign(this, { RepoDetailsService, $state, $stateParams }); + this.error = $stateParams.error; } getStatsUrls() { const params = this.RepoDetailsService.getNameAndOwnerFromUrl(this.githubUrl); if (params) { - this.loadingRepo = true; this.error = null; - // this.RepoDetailsService.getStats(params).then(() => { - this.$state.go('repo-health', params); - } else { - this.error = 'This repo does not exist'; - this.loadingRepo = false; - }; + this.$state.go('repo-health', params); + } else { + this.error = true; } } + } }; export default searchComponent; diff --git a/repo_health/index/static/client/src/components/search/search.html b/repo_health/index/static/client/src/components/search/search.html index 4cff333..ab584b4 100644 --- a/repo_health/index/static/client/src/components/search/search.html +++ b/repo_health/index/static/client/src/components/search/search.html @@ -5,7 +5,7 @@ Error - {{$ctrl.error}} + {{$ctrl.errorMsg}} diff --git a/repo_health/index/static/client/src/components/search/search.module.js b/repo_health/index/static/client/src/components/search/search.module.js index 66a81a8..75e7b2a 100644 --- a/repo_health/index/static/client/src/components/search/search.module.js +++ b/repo_health/index/static/client/src/components/search/search.module.js @@ -21,7 +21,8 @@ const components = angular $stateProvider.state('search', { url: '/search', - template: '' + template: '', + params: { error: false } }) }) .name; diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index b072eee..7a34433 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -17,6 +17,7 @@ import uiRouter from 'angular-ui-router'; import resources from './resources'; import components from 'components/components.module.js'; import mainComponent from './main.component'; +import RepoDetailsController from 'components/repo-details/repo-details.controller'; //Styles import 'global.css'; @@ -35,28 +36,17 @@ export const main = angular.module('repo-health', [ $urlRouterProvider.otherwise('/search'); $stateProvider.state('repo-health', { url: '/repo-health/:owner__login/:name', - // controller: class RepoHealthController { - // constructor(details) { - // this.details = details; - // } - // }, - // controllerAs: '$ctrl', resolve: { - statsUrls: (RepoDetailsService, $stateParams) => { - return RepoDetailsService.getStatsUrls($stateParams); + statsUrls: (RepoDetailsService, $stateParams, $state) => { + return RepoDetailsService.getStatsUrls($stateParams) + .then(resp => {return resp;}, () => { return {error:true}}); } }, views: { 'repo-details': { - controller: class DetailsController { - constructor(detailsUrl) { - this.detailsUrl = detailsUrl; - } - }, + controller: RepoDetailsController, resolve: { - detailsUrl: (statsUrls) => { - return statsUrls["repo_details_url"]; - } + detailsUrl: (statsUrls) => {return statsUrls["repo_details_url"];} }, controllerAs: '$ctrl', template: '', From fca2317fbdd7269e64d078abcdf7606ab1e49de1 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 20 Mar 2017 22:42:30 -0500 Subject: [PATCH 55/99] Setup example chart with some data. --- .../base-component/base.template.html | 22 +++----- .../pull-req-stats.component.js | 51 ++++++++++++++----- .../repo-details/repo-details.component.js | 3 +- .../repo-details/repo-details.spec.js | 22 ++++---- .../index/static/client/src/main.module.js | 12 ++--- repo_health/index/static/package.json | 1 + 6 files changed, 65 insertions(+), 46 deletions(-) diff --git a/repo_health/index/static/client/src/components/base-component/base.template.html b/repo_health/index/static/client/src/components/base-component/base.template.html index 00082f2..7aef888 100644 --- a/repo_health/index/static/client/src/components/base-component/base.template.html +++ b/repo_health/index/static/client/src/components/base-component/base.template.html @@ -15,24 +15,16 @@ -
-
Language: {{$ctrl.stats.language}}
-
Contributions: {{$ctrl.stats.contribs_count}}
-
- -
-
Watchers: {{$ctrl.stats.watchers_count}}
-
Commits: {{$ctrl.stats.commits_count}}
-
-
-
Milestones: {{$ctrl.stats.milestones_count}}
-
Forks: {{$ctrl.stats.forks_count}}
+
+
+
{{k}}: {{v}}
+
-
-
Pull Req: {{$ctrl.stats.prs_last_year}}
-
+
diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index dd6f0e8..b431980 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -18,7 +18,45 @@ const pullReqStatsComponent = { controller: class pullReqStatsComponent { stats = null; loadingStats = true; - loadingMsg = "Loading issue stats..." + loadingMsg = "Loading issue stats..."; + + labels = ['Jan', 'feb', 'Mar', 'April', 'May', 'Jun', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + series = ['Series A', 'Series B']; + data = [ + [65, 59, 80, 81, 56, 55, 40], + [28, 48, 40, 19, 86, 27, 90] + ]; + onClick = function (points, evt) { + console.log(points, evt); + }; + onHover = function (points) { + if (points.length > 0) { + console.log('Point', points[0].value); + } else { + console.log('No point'); + } + }; + datasetOverride = [{ yAxisID: 'y-axis-1' }, { yAxisID: 'y-axis-2' }]; + + options = { + scales: { + yAxes: [ + { + id: 'y-axis-1', + type: 'linear', + display: true, + position: 'left' + }, + { + id: 'y-axis-2', + type: 'linear', + display: true, + position: 'right' + } + ] + } + }; + constructor( $http) { 'ngInject'; Object.assign(this, { $http }); @@ -29,17 +67,6 @@ const pullReqStatsComponent = { this.stats = stats.data; this.loadingStats = false; }) - // this.RepoDetailsService.getStats(this.$stateParams).then( () => { - // let params = { - // id: this.RepoDetailsService.repoDetails.id, - // verb: 'pull-requests' - // } - // this.$repo.get('pullReqStats', params).then(stats => { - // this.stats = stats; - // this.loadingStats = false; - // }, () => {this.$state.go('search')} - // ); - // }); } } }; diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index 03da839..388f807 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -18,7 +18,8 @@ const repoDetailsComponent = { controller: class repoDetailsComponent { loadingStats = true; - loadingMsg = "Loading general repo stats..." + loadingMsg = "Loading general repo stats..."; + stats = null; constructor($http) { 'ngInject'; diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index 5c62a07..7b2f0b1 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -50,17 +50,17 @@ describe('Repo Details', () => { // }); }); - describe('getStatsUrls', () => { - it('should make a call to service', () => { - spyOn(controller.RepoDetailsService, 'getStatsUrls').and.returnValue($q.resolve({ name: 'cakephp' })); - expect(controller.RepoDetailsService.getStatsUrls).not.toHaveBeenCalled(); - controller.getStatsUrls(); - $rootScope.$apply(); - expect(controller.loadingRepo).toBeFalsy(); - expect(controller.details).toEqual({ name: 'cakephp' }); - expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); - }); - }); + // describe('getStatsUrls', () => { + // it('should make a call to service', () => { + // spyOn(controller.RepoDetailsService, 'getStatsUrls').and.returnValue($q.resolve({ name: 'cakephp' })); + // expect(controller.RepoDetailsService.getStatsUrls).not.toHaveBeenCalled(); + // controller.getStatsUrls(); + // $rootScope.$apply(); + // expect(controller.loadingRepo).toBeFalsy(); + // expect(controller.details).toEqual({ name: 'cakephp' }); + // expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); + // }); + // }); }); describe('RepoDetailsService', () => { diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index 7a34433..c8e0b76 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -14,6 +14,7 @@ import angular from 'angular'; import ngMaterial from 'angular-material'; import uiRouter from 'angular-ui-router'; +import 'angular-chart.js'; import resources from './resources'; import components from 'components/components.module.js'; import mainComponent from './main.component'; @@ -26,12 +27,12 @@ export const main = angular.module('repo-health', [ uiRouter, ngMaterial, components, - resources + resources, + 'chart.js' ]) .component('main', mainComponent) .config(($locationProvider, $urlRouterProvider, $mdThemingProvider, $stateProvider) => { 'ngInject'; - $locationProvider.hashPrefix(''); $urlRouterProvider.otherwise('/search'); $stateProvider.state('repo-health', { @@ -46,7 +47,7 @@ export const main = angular.module('repo-health', [ 'repo-details': { controller: RepoDetailsController, resolve: { - detailsUrl: (statsUrls) => {return statsUrls["repo_details_url"];} + detailsUrl: (statsUrls) => { return statsUrls["repo_details_url"]; } }, controllerAs: '$ctrl', template: '', @@ -58,10 +59,7 @@ export const main = angular.module('repo-health', [ } }, controllerAs: '$ctrl', - resolve: { - prStatsUrl: (statsUrls) => { - return statsUrls['pr_stats_url']; - } + resolve: { prStatsUrl: (statsUrls) => { return statsUrls['pr_stats_url']; } }, template: '' } diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index 57b1dd5..ee0f604 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -9,6 +9,7 @@ "angular": "^1.6.2", "angular-animate": "^1.6.2", "angular-aria": "^1.6.2", + "angular-chart.js": "^1.1.1", "angular-material": "^1.1.3", "angular-resource": "^1.6.2", "angular-ui-router": "^0.4.2", From fab00fb643909a8f540041fb8379e100962ec8fb Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 22 Mar 2017 17:54:18 -0500 Subject: [PATCH 56/99] Fix up the jasmine tests. --- .../pull-req-stats/pull-req-stats.spec.js | 24 ++- .../repo-details/repo-details.service.js | 3 - .../repo-details/repo-details.spec.js | 149 ++++++++---------- .../src/components/search/search.component.js | 2 +- .../src/components/search/search.spec.js | 18 +-- 5 files changed, 94 insertions(+), 102 deletions(-) diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js index a4e8f69..af3c22c 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js @@ -22,19 +22,35 @@ describe('Pull Req Stats', () => { )); describe('PullReqStatsController', () => { - let $componentController; - let controller; + let $componentController, $httpBackend, $apiUrl; + let controller, getPrStatsUrl; beforeEach(inject(($injector) => { $componentController = $injector.get('$componentController'); - controller = $componentController('pullReqStats'); + $httpBackend = $injector.get('$httpBackend'); + $apiUrl = $injector.get('$apiUrl'); + getPrStatsUrl = `${$apiUrl}/${jasmine.any(Number)}/pull-requests`; + controller = $componentController('pullReqStats', null, {prStatsUrl: getPrStatsUrl}); + $httpBackend.when('GET', getPrStatsUrl).respond(200, {some: 'cakephp', data: 15}); + })); + afterEach(() => { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + describe('constructor', () => { + it('should setup the controller', () => { expect(controller).toBeDefined(); }); - }); + it('should make a request to get the stats in the $onInit method', () => { + $httpBackend.expectGET(getPrStatsUrl) + controller.$onInit(); + $httpBackend.flush(); + }) + }); }); }); \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js index 9a77d91..72b5560 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.service.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.service.js @@ -22,9 +22,6 @@ class RepoDetailsService { /* Gets the last two strings on a url */ getNameAndOwnerFromUrl(url = '') { - // if (url.search('github.com') == -1) { - // return; - // } const pathArray = url.replace(/.*github.com\//, '').split('/'); const name = pathArray.pop(); diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index 7b2f0b1..ad17e83 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -13,100 +13,85 @@ const module = angular.mock.module; describe('Repo Details', () => { - let $rootScope; - let $q; - - beforeEach(module( - 'app.resources', - 'components.search', - 'components.repo-details') - ); - - describe('RepoDetailsController', () => { - let $componentController; - let controller; + let $httpBackend; + let $apiUrl, getStatsReqUrl, getDetailsUrl; + beforeEach(module( + 'app.resources', + 'components.search', + 'components.repo-details', + )); beforeEach(inject(($injector) => { - $componentController = $injector.get('$componentController'); - $rootScope = $injector.get('$rootScope'); - $q = $injector.get('$q'); - controller = $componentController('repoDetails'); + $httpBackend = $injector.get("$httpBackend"); + $apiUrl = $injector.get('$apiUrl'); + getStatsReqUrl = `${$apiUrl}?name=cakephp&owner__login=cakephp`; + getDetailsUrl = `${$apiUrl}/${jasmine.any(Number)}`; + })); - describe('constructor', () => { - it('should setup the controller', () => { - expect(controller).toBeDefined(); - }); - - it('should setup loadingRepo and details', () => { - expect(controller.loadingStats).toBeTruthy(); - expect(controller.stats).toBeNull(); - }); - - // it('should setup RepoDetailsService, $state, $stateParams', () => { - // expect(controller.RepoDetailsService).toBeDefined(); - // expect(controller.$state).toBeDefined(); - // expect(controller.$stateParams).toBeDefined(); - // }); + afterEach(() => { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); }); - // describe('getStatsUrls', () => { - // it('should make a call to service', () => { - // spyOn(controller.RepoDetailsService, 'getStatsUrls').and.returnValue($q.resolve({ name: 'cakephp' })); - // expect(controller.RepoDetailsService.getStatsUrls).not.toHaveBeenCalled(); - // controller.getStatsUrls(); - // $rootScope.$apply(); - // expect(controller.loadingRepo).toBeFalsy(); - // expect(controller.details).toEqual({ name: 'cakephp' }); - // expect(controller.RepoDetailsService.getStats).toHaveBeenCalled(); - // }); - // }); - }); - - describe('RepoDetailsService', () => { - let RepoDetailsService; - let $httpBackend; - let $apiUrl; + describe('RepoDetailsController', () => { + let $componentController; + let controller; - beforeEach(inject(($injector) => { - $rootScope = $injector.get('$rootScope'); - $q = $injector.get('$q'); - $httpBackend = $injector.get('$httpBackend'); - $apiUrl = $injector.get('$apiUrl'); - RepoDetailsService = $injector.get('RepoDetailsService'); - })); + beforeEach(inject(($injector) => { + $componentController = $injector.get('$componentController'); + controller = $componentController('repoDetails', null, { detailsUrl: getDetailsUrl}); + $httpBackend.when('GET', getDetailsUrl).respond(200, {name: 'cakephp', watchers: 15}); + })); - describe('getNameAndOwnerFromUrl', () => { - it('should return name and owner', () => { - expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name/repo')).toEqual({ name: 'repo', owner__login: 'name' }); - }); - - it('should return undefined', () => { - expect(RepoDetailsService.getNameAndOwnerFromUrl()).toBeUndefined(); - expect(RepoDetailsService.getNameAndOwnerFromUrl('not a url')).toBeUndefined(); - expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name')).toBeUndefined(); - }); + describe('constructor', () => { + it('should setup the controller', () => { + expect(controller).toBeDefined(); + expect(controller.loadingStats).toBeTruthy(); + expect(controller.stats).toBeNull(); + }); + + it('should request the details in the $onInit method', () => { + $httpBackend.expectGET(getDetailsUrl); + controller.$onInit(); + $httpBackend.flush(); + }); + }); }); - describe('getStatsUrls', () => { - it('should return a promise if repoDetails exists', () => { - RepoDetailsService.repoDetails = { name: 'cakephp', watchers: 123 }; - RepoDetailsService.getStats().then(details => { - expect(details).toEqual(RepoDetailsService.repoDetails); + describe('RepoDetailsService', () => { + let RepoDetailsService; + + beforeEach(inject(($injector) => { + RepoDetailsService = $injector.get('RepoDetailsService'); + })); + + describe('getNameAndOwnerFromUrl', () => { + it('should return name and owner', () => { + expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name/repo')).toEqual({ + name: 'repo', + owner__login: 'name' + }); + }); + + it('should return undefined', () => { + expect(RepoDetailsService.getNameAndOwnerFromUrl()).toBeUndefined(); + expect(RepoDetailsService.getNameAndOwnerFromUrl('not a url')).toBeUndefined(); + expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name')).toBeUndefined(); + }); }); - $rootScope.$apply(); - }); - it('should set repoDetails if it doesn\'t exist', () => { - $httpBackend.when('GET', `${$apiUrl}?name=cakephp&owner__login=cakephp`).respond(200, { name: 'cakephp', watchers: 15 }); - RepoDetailsService.getStats({ name: 'cakephp', owner__login: 'cakephp' }).then(details => { - expect(details).toEqual(RepoDetailsService.repoDetails); + describe('getStatsUrls', () => { + beforeEach(() => { + $httpBackend.when('GET', getStatsReqUrl).respond(200, {repo_details_url: 'cakephp', pr_stats_url: 15}); + }); + + it('should make a request to get the urls', () => { + $httpBackend.expectGET(getStatsReqUrl); + RepoDetailsService.getStatsUrls({name: 'cakephp', owner__login: 'cakephp'}); + $httpBackend.flush(); + + }); }); - $httpBackend.flush(); - $rootScope.$apply(); - expect(RepoDetailsService.repoDetails.name).toEqual('cakephp'); - expect(RepoDetailsService.repoDetails.watchers).toEqual(15); - }); }); - }); }); \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/search/search.component.js b/repo_health/index/static/client/src/components/search/search.component.js index bc3fc7b..0bdc702 100644 --- a/repo_health/index/static/client/src/components/search/search.component.js +++ b/repo_health/index/static/client/src/components/search/search.component.js @@ -22,7 +22,7 @@ const searchComponent = { constructor(RepoDetailsService, $state, $stateParams) { 'ngInject'; Object.assign(this, { RepoDetailsService, $state, $stateParams }); - this.error = $stateParams.error; + this.error = $stateParams.error || null; } getStatsUrls() { diff --git a/repo_health/index/static/client/src/components/search/search.spec.js b/repo_health/index/static/client/src/components/search/search.spec.js index 5d45f8d..686f574 100644 --- a/repo_health/index/static/client/src/components/search/search.spec.js +++ b/repo_health/index/static/client/src/components/search/search.spec.js @@ -43,38 +43,32 @@ describe('Search', () => { expect(controller).toBeDefined(); }); it('should setup loadingRepo and error', () => { - expect(controller.loadingRepo).toBeFalsy(); expect(controller.error).toBeNull(); }); }); describe('getStatsUrls', () => { - let getStats; it('should not make a call if url is invalid', () => { - spyOn(controller.RepoDetailsService, 'getStats'); + spyOn(controller.$state, 'go'); controller.githubUrl = 'This not a url'; controller.getStatsUrls(); - expect(controller.loadingRepo).toBeTruthy(); - expect(controller.RepoDetailsService.getStats).not.toHaveBeenCalled(); + expect(controller.error).toBeTruthy(); + expect(controller.$state.go).not.toHaveBeenCalledWith('repo-health'); }); it('should make a call to getStatsUrls on the service', () => { - spyOn(controller.RepoDetailsService, 'getStats').and.returnValue($q.resolve({ name: 'cakephp' })); + spyOn(controller.RepoDetailsService, 'getStatsUrls').and.returnValue($q.resolve({ name: 'cakephp' })); controller.githubUrl = 'https://github.com/cakephp/cakephp'; controller.getStatsUrls(); - expect(controller.loadingRepo).toBeTruthy(); - // expect(controller.RepoDetailsService.getStatsUrls).toHaveBeenCalled(); + expect(controller.RepoDetailsService.getStatsUrls).toHaveBeenCalled(); }); it('should set an error if it fails', () => { - // spyOn(controller.RepoDetailsService, 'getStatsUrls').and.returnValue($q.reject('error')); controller.githubUrl = 'https://github.com/cakephp/'; controller.getStatsUrls(); $rootScope.$apply(); - expect(controller.loadingRepo).toBeFalsy(); - expect(controller.error).toEqual('This repo does not exist'); - // expect(controller.RepoDetailsService.getStatsUrls).toHaveBeenCalled(); + expect(controller.error).toBeTruthy(); }); }); }); From bbca5828eb61d33f632ba34a1855862fe7a843ac Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 22 Mar 2017 18:43:02 -0500 Subject: [PATCH 57/99] Check for presence of urls. --- .../pull-req-stats/pull-req-stats.component.js | 4 +++- .../components/repo-details/repo-details.component.js | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index b431980..9cca8ed 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -63,10 +63,12 @@ const pullReqStatsComponent = { } $onInit() { + if (this.prStatsUrl) { this.$http.get(this.prStatsUrl).then(stats => { this.stats = stats.data; this.loadingStats = false; - }) + }); + } } } }; diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index 388f807..f44a3bb 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -27,10 +27,12 @@ const repoDetailsComponent = { } $onInit() { - this.$http.get(this.detailsUrl).then(details => { - this.stats = details.data; - this.loadingStats = false; - }); + if (this.detailsUrl) { + this.$http.get(this.detailsUrl).then(details => { + this.stats = details.data; + this.loadingStats = false; + }); + } } } }; From 20e39f9389130ffcd810f730aaface390c59a729 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 22 Mar 2017 20:55:02 -0500 Subject: [PATCH 58/99] Rework Project serializer to new schema. --- repo_health/gh_projects/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index 6322be0..bf18fa2 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -21,6 +21,7 @@ from repo_health.gh_pull_requests.serializers import GhPullRequestStatsSerializer from .models import GhProject from .serializers import GhProjectSerializer, StatsUrlsSerializer +from repo_health.metrics.serializers import ResponseSerializer class GhProjectViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): @@ -38,7 +39,9 @@ def retrieve(self, r, *args, **kwargs): :return: Response """ obj = self.get_object() - return Response(GhProjectSerializer(obj).data) + repo_data = GhProjectSerializer(obj).data + response = ResponseSerializer(repo_data) + return Response(response.data) def list(self, r, *args, **kwargs): """ From ebc114468405f7b04d5b2a13a0393f5ed12ccd3e Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 22 Mar 2017 21:13:20 -0500 Subject: [PATCH 59/99] Rework Project serializer to new schema. Rest of the files --- docs/rest_api/Response.md | 15 ----- .../serializers/GhProjectSerializer.py | 59 +++++++++++++------ repo_health/gh_projects/tests.py | 4 +- .../metrics/serializers/ChartSerializer.py | 20 +++++++ .../serializers/MetricFieldSerializer.py | 37 ++++++++++++ .../metrics/serializers/ResponseSerializer.py | 12 +++- repo_health/metrics/serializers/__init__.py | 15 +++++ 7 files changed, 127 insertions(+), 35 deletions(-) create mode 100644 repo_health/metrics/serializers/ChartSerializer.py create mode 100644 repo_health/metrics/serializers/MetricFieldSerializer.py diff --git a/docs/rest_api/Response.md b/docs/rest_api/Response.md index 7596e43..181f4e4 100644 --- a/docs/rest_api/Response.md +++ b/docs/rest_api/Response.md @@ -5,21 +5,6 @@ Represents a response schema for a request to the API. A list of metrics are ret Comments are added for clarification. - ``` - [ - { - display: string, //display name of the metric - ordering: int, //order if the metric in UI - metric: int | [int] | string, //Actual data. Array of ints if it is a chart - chart_type: null | string, //Type of chart if chart is used - chart_name: null | stirng, //Name of chart to allow multiple metrics on one chart - - }, - ... - ] - ``` - ## OR - ``` { ...//Maybe some other data defining the Response to the UI diff --git a/repo_health/gh_projects/serializers/GhProjectSerializer.py b/repo_health/gh_projects/serializers/GhProjectSerializer.py index 436c99b..c628875 100644 --- a/repo_health/gh_projects/serializers/GhProjectSerializer.py +++ b/repo_health/gh_projects/serializers/GhProjectSerializer.py @@ -10,12 +10,17 @@ Serializer for a GitHub repo. """ -from rest_framework.serializers import ModelSerializer, SerializerMethodField +from rest_framework.serializers import Serializer, SerializerMethodField from repo_health.gh_users.models import GhUser +from repo_health.metrics.serializers import MetricField from ..models import GhProject -class GhProjectSerializer(ModelSerializer): +class GhProjectSerializer(Serializer): + """ + Calculates the metrics for a repo. Each field returns a list corresponding to the fields of the FieldSerializer. + + """ _contribs_count = None _watch_not_contribs_count = None _orgs_of_contribs_count = None @@ -23,6 +28,14 @@ class GhProjectSerializer(ModelSerializer): _commits_count = None _latest_commit = None + # Fields found directly on the model + language = SerializerMethodField() + name = SerializerMethodField() + description = SerializerMethodField() + forked_from = SerializerMethodField() + created_at = SerializerMethodField() + + # Fields with calculations/aggregations contribs_count = SerializerMethodField() watchers_count = SerializerMethodField() commits_count = SerializerMethodField() @@ -31,7 +44,8 @@ class GhProjectSerializer(ModelSerializer): labels_count = SerializerMethodField() orgs_of_contribs_count = SerializerMethodField() owned_by_org = SerializerMethodField() - forks_count = SerializerMethodField() + forks_count = SerializerMethodField() + def __init__(self, *args, **kwargs): """ @@ -47,36 +61,47 @@ def __init__(self, *args, **kwargs): self._latest_commit = commits.first().created_at self._orgs_of_contribs_count = GhUser.objects.filter(members__in=commit_users).exclude(id=repo.owner.id).count() + def get_language(self, repo): + return MetricField(True, 'Language', 2, None, repo.language) + + def get_name(self, repo): + return MetricField(True, 'Name', 0, None, repo.name) + + def get_description(self, repo): + return MetricField(True, 'Description', 1, None, repo.description) + + def get_forked_from(self, repo): + return MetricField(True, 'Has upstream', 3, None, repo.forked_from.name) + + def get_created_at(self, repo): + return MetricField(True, 'Age', 4, 'date', repo.created_at) + def get_orgs_of_contribs_count(self, repo): - return self._orgs_of_contribs_count + return MetricField(True, "Number of outside organizations with commits", 5, None, self._orgs_of_contribs_count) def get_contribs_count(self, obj): - return self._contribs_count + return MetricField(True, 'Number of contributrs', 6, None, self._contribs_count) def get_commits_count(self, obj): - return self._commits_count + return MetricField(True, 'Number of commits', 7, None, self._commits_count) def get_maintainers_count(self, repo): - return repo.maintainers.count() + return MetricField(True, 'Number of maintainers', 8, None, repo.maintainers.count()) def get_watchers_count(self, repo): - return repo.watchers.count() + return MetricField(True, 'Number of watchers', 9, None, repo.watchers.count()) def get_milestones_count(self, repo): - return repo.milestones.count() + return MetricField(True, 'Number of milestones', 10, None, repo.milestones.count()) def get_latest_commit_created_at(self, repo): - return self._latest_commit + return MetricField(True, 'Age of latest commit', 11, 'date', self._latest_commit) def get_labels_count(self, repo): - return repo.labels.count() + return MetricField(True, 'Number of labels', 12, None, repo.labels.count()) def get_owned_by_org(self, repo): - return repo.is_owned_by_org() + return MetricField(True, 'Is owner an organization', 13, None, repo.is_owned_by_org()) def get_forks_count(self, repo): - return repo.forks.all().count() - - class Meta: - model = GhProject - exclude = ['commits_m2m', 'maintainers', 'watchers', 'url', 'forks', ] + return MetricField(True, 'Number of forks', 14, None, repo.forks.all().count()) diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 577a2fb..59fc217 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -70,8 +70,10 @@ def setUp(self): def test_api_get_project(self): r = self.client.get(dj_reverse('gh-project-detail', args=[self.project.id])) + print(r.data) self.assertTrue(status.is_success(r.status_code)) - self.assertEqual(r.data.get('id'), self.project.id) + self.assertTrue(isinstance(r.data.get('metrics'), list)) + self.assertTrue(isinstance(r.data.get('charts'), list) and len(r.data['charts']) is 0) #test with bad input max_id = GhProject.objects.all().aggregate(m.Max('id')).get('id__max') diff --git a/repo_health/metrics/serializers/ChartSerializer.py b/repo_health/metrics/serializers/ChartSerializer.py new file mode 100644 index 0000000..444a778 --- /dev/null +++ b/repo_health/metrics/serializers/ChartSerializer.py @@ -0,0 +1,20 @@ +""" +ChartSerializer.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Model data around a chart in the UI. +""" + + +from rest_framework import serializers as s + + +class ChartSerializer(s.Serializer): + chart_type = s.IntegerField() + label = s.CharField() + x_names = s.SerializerMethodField() diff --git a/repo_health/metrics/serializers/MetricFieldSerializer.py b/repo_health/metrics/serializers/MetricFieldSerializer.py new file mode 100644 index 0000000..9f98659 --- /dev/null +++ b/repo_health/metrics/serializers/MetricFieldSerializer.py @@ -0,0 +1,37 @@ +""" +FieldSerializer.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Model the field in the serializer for now. Possible we store this in the database at some point in the future. +""" + + +from rest_framework import serializers as s + + +class MetricField(object): + is_displayed = display_name = ordering = chart_name = raw_data = None + + def __init__(self, is_displayed, display_name, ordering, chart_name, raw_data): + self.is_displayed = is_displayed + self.display_name = display_name + self.ordering = ordering + self.chart_name = chart_name + self.raw_data = raw_data + + +class MetricFieldSerializer(s.Serializer): + + is_displayed = s.BooleanField() + display_name = s.CharField() + ordering = s.IntegerField() + chart_name = s.CharField() + raw_data = s.SerializerMethodField() + + def get_raw_data(self, obj): + return obj.raw_data diff --git a/repo_health/metrics/serializers/ResponseSerializer.py b/repo_health/metrics/serializers/ResponseSerializer.py index bc202b7..ac30a82 100644 --- a/repo_health/metrics/serializers/ResponseSerializer.py +++ b/repo_health/metrics/serializers/ResponseSerializer.py @@ -1,5 +1,5 @@ """ -ResponseSerializers.py - (C) Copyright - 2017 +ResponseSerializer.py - (C) Copyright - 2017 This software is copyrighted to contributors listed in CONTRIBUTIONS.md. SPDX-License-Identifier: MIT @@ -12,15 +12,23 @@ from rest_framework import serializers as s +from .MetricFieldSerializer import MetricFieldSerializer class ResponseSerializer(s.Serializer): + _metrics = None charts = s.SerializerMethodField() metrics = s.SerializerMethodField() + def __init__(self, repo_data_dict): + super().__init__(repo_data_dict) + self._metrics = [] + for k, v in repo_data_dict.items(): + self._metrics.append(MetricFieldSerializer(v).data) + def get_charts(self, obj): return [] def get_metrics(self, obj): - return [] \ No newline at end of file + return self._metrics diff --git a/repo_health/metrics/serializers/__init__.py b/repo_health/metrics/serializers/__init__.py index e69de29..e3fa361 100644 --- a/repo_health/metrics/serializers/__init__.py +++ b/repo_health/metrics/serializers/__init__.py @@ -0,0 +1,15 @@ +""" +__init__.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Import all classes from package. +""" + +from .ChartSerializer import ChartSerializer +from .MetricFieldSerializer import MetricFieldSerializer, MetricField +from .ResponseSerializer import ResponseSerializer From 0b6039feccc7afdd983a29eb15c896fb4a0db511 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 22 Mar 2017 21:27:48 -0500 Subject: [PATCH 60/99] Add a couple TODOs --- repo_health/metrics/serializers/ResponseSerializer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/repo_health/metrics/serializers/ResponseSerializer.py b/repo_health/metrics/serializers/ResponseSerializer.py index ac30a82..19b9786 100644 --- a/repo_health/metrics/serializers/ResponseSerializer.py +++ b/repo_health/metrics/serializers/ResponseSerializer.py @@ -26,7 +26,9 @@ def __init__(self, repo_data_dict): self._metrics = [] for k, v in repo_data_dict.items(): self._metrics.append(MetricFieldSerializer(v).data) + # Do what is need to build the chart response here. + # TODO Implement charts in response def get_charts(self, obj): return [] From 33c33bcadcdf291cfce4dd7f70435b430e98038a Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 22 Mar 2017 23:14:07 -0500 Subject: [PATCH 61/99] Display metrics in an interative manner. --- .../serializers/GhProjectSerializer.py | 8 +++--- .../base-component/base.template.html | 26 ++++++++++--------- .../repo-details/repo-details.component.js | 25 +++++++++++++++--- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/repo_health/gh_projects/serializers/GhProjectSerializer.py b/repo_health/gh_projects/serializers/GhProjectSerializer.py index c628875..27a64e7 100644 --- a/repo_health/gh_projects/serializers/GhProjectSerializer.py +++ b/repo_health/gh_projects/serializers/GhProjectSerializer.py @@ -65,16 +65,16 @@ def get_language(self, repo): return MetricField(True, 'Language', 2, None, repo.language) def get_name(self, repo): - return MetricField(True, 'Name', 0, None, repo.name) + return MetricField(True, None, 0, None, repo.name) def get_description(self, repo): - return MetricField(True, 'Description', 1, None, repo.description) + return MetricField(True, None, 1, None, repo.description) def get_forked_from(self, repo): - return MetricField(True, 'Has upstream', 3, None, repo.forked_from.name) + return MetricField(True, 'Has upstream', 3, None, repo.forked_from.name if repo.forked_from else None) def get_created_at(self, repo): - return MetricField(True, 'Age', 4, 'date', repo.created_at) + return MetricField(True, 'Created at', 4, 'date', repo.created_at) def get_orgs_of_contribs_count(self, repo): return MetricField(True, "Number of outside organizations with commits", 5, None, self._orgs_of_contribs_count) diff --git a/repo_health/index/static/client/src/components/base-component/base.template.html b/repo_health/index/static/client/src/components/base-component/base.template.html index 7aef888..336606d 100644 --- a/repo_health/index/static/client/src/components/base-component/base.template.html +++ b/repo_health/index/static/client/src/components/base-component/base.template.html @@ -8,23 +8,25 @@
- +
+ - {{::$ctrl.stats.name}} - {{::$ctrl.stats.description}} + {{ $ctrl.stats[2 * i].raw_data }} + {{ $ctrl.stats[2 * i + 1].raw_data }} - + -
-
-
{{k}}: {{v}}
-
-
+
{{$ctrl.stats[(2 * i)].display_name}}: + {{ $ctrl.getRawDataForChartName(2 * i) }} +
+
{{$ctrl.stats[ (2 * i + 1) ].display_name}}: + {{ $ctrl.getRawDataForChartName((2 * i + 1)) }} +
- + + +
diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index f44a3bb..7fc763a 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -12,6 +12,13 @@ import template from '../base-component/base.template'; +/** + * Tracks constants for chart names. + */ +const chartNameEnum = { + dateChart: 'date' // Track date as a chart to tell what metrics are dates +} + const repoDetailsComponent = { template, bindings: {detailsUrl: '='}, @@ -20,20 +27,32 @@ const repoDetailsComponent = { loadingStats = true; loadingMsg = "Loading general repo stats..."; stats = null; + numOfStatsSections = 0; - constructor($http) { + constructor($http, $filter) { 'ngInject'; - Object.assign(this, { $http }); + Object.assign(this, { $http, $filter }); } $onInit() { if (this.detailsUrl) { this.$http.get(this.detailsUrl).then(details => { - this.stats = details.data; + this.stats = this.$filter('orderBy')(details.data.metrics, 'ordering'); + this.numOfStatsSections = new Array(this.stats.length / 2).fill().map((x,i)=>i); this.loadingStats = false; }); } } + + getRawDataForChartName(ind) { + let rawData = this.stats[ind].raw_data; + switch ( this.stats[ind].chart_name ) { + case chartNameEnum.dateChart: + rawData = this.$filter('date')(rawData); + break; + } + return rawData || 'No'; + } } }; From def86c08125dbbd54832155b4606c019a97576c6 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Thu, 23 Mar 2017 16:33:23 -0500 Subject: [PATCH 62/99] Spelling fix. --- repo_health/gh_projects/serializers/GhProjectSerializer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/repo_health/gh_projects/serializers/GhProjectSerializer.py b/repo_health/gh_projects/serializers/GhProjectSerializer.py index 27a64e7..8ae3c93 100644 --- a/repo_health/gh_projects/serializers/GhProjectSerializer.py +++ b/repo_health/gh_projects/serializers/GhProjectSerializer.py @@ -13,7 +13,6 @@ from rest_framework.serializers import Serializer, SerializerMethodField from repo_health.gh_users.models import GhUser from repo_health.metrics.serializers import MetricField -from ..models import GhProject class GhProjectSerializer(Serializer): @@ -80,7 +79,7 @@ def get_orgs_of_contribs_count(self, repo): return MetricField(True, "Number of outside organizations with commits", 5, None, self._orgs_of_contribs_count) def get_contribs_count(self, obj): - return MetricField(True, 'Number of contributrs', 6, None, self._contribs_count) + return MetricField(True, 'Number of contributors', 6, None, self._contribs_count) def get_commits_count(self, obj): return MetricField(True, 'Number of commits', 7, None, self._commits_count) From 9335841813bb3572d9a25b6f32e84f386f492a0b Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 1 Mar 2017 21:01:24 -0600 Subject: [PATCH 63/99] Misspelling. --- docs/rest_api/PullRequests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rest_api/PullRequests.md b/docs/rest_api/PullRequests.md index 41fdced..2dd604e 100644 --- a/docs/rest_api/PullRequests.md +++ b/docs/rest_api/PullRequests.md @@ -21,6 +21,6 @@ A GET request is made to: } ``` -## Possilble future metrics +## Possible future metrics - upstream/downstream pr count and count of merged From 630f50cf08ecc6319dd46cbf0316738049c62829 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 5 Mar 2017 12:04:28 -0600 Subject: [PATCH 64/99] Experiments on pr average lifetime. --- .../GhPullRequestStatsSerializer.py | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 2828d93..830064d 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -15,7 +15,7 @@ from django.db import models as m from rest_framework import serializers as s from repo_health.gh_users.models import GhUser -from ..models import GhPullRequestHistory +from ..models import GhPullRequestHistory, GhPullRequest class GhPullRequestStatsSerializer(s.Serializer): @@ -102,12 +102,32 @@ def get_avg_lifetime(self, repo): avg = (td / closed).days # Save this code to hopefully aggregate the average at the database level sometime. + agg = GhPullRequest.objects.raw( + "SELECT `pull_requests`.`id`, `pull_request_history`.`created_at` as `created_at`, `t`.`created_at` as " + + "`closed_at` from `pull_requests` join `pull_request_history` on `pull_request_history`." + + "`pull_request_id` = `pull_requests`.`id` join `pull_request_history` `t` on`pull_request_history`." + + "`pull_request_id` = `pull_requests`.`id` where `t`.`action` = 'closed' and `pull_request_history`." + + "`action` = 'opened' and `pull_requests`.`base_repo_id` = %s", [repo.id], + + ) # agg = repo.prs_to \ - # .annotate(closed_at=m.Case(m.When(m.Q(history__action=GhPullRequestHistory.CLOSED_ACTION) & m.Q(history__created_at__isnull=False)), then=m.F('history__created_at'))) \ - # .annotate(created_at=m.Case(m.When(m.Q(history__action=GhPullRequestHistory.OPENED_ACTION) & m.Q(history__created_at__isnull=False)), then=m.F('history__created_at'))) \ - # .annotate(elapsed=m.F('closed_at')) \ - # .values('created_at', 'closed_at', 'id', 'elapsed') - # .aggregate(life=m.Max('closed_at', output_field=m.DateTimeField())) + # .annotate(closed_at=m.Case( + # m.When( + # history__action=GhPullRequestHistory.CLOSED_ACTION, + # then=m.F('history__created_at'), + # ), output_field=m.DateTimeField(), + # )) \ + # .annotate(created_at=m.Case( + # m.When( + # history__action=GhPullRequestHistory.OPENED_ACTION, + # then=m.F('history__created_at'), + # ), output_field=m.DateTimeField(), + # )) \ + # .values('created_at', 'closed_at', 'id', 'history__action') \ + # .exclude(m.Q(history__action=GhPullRequestHistory.CLOSED_ACTION) & m.Q(closed_at__isnull=True)).query + # .aggregate(avg=m.Avg(m.F('created_at') - m.F('closed_at'), output_field=m.DurationField())) + print(agg) + return avg def get_not_maintainer_prs(self, repo): From 4982e6c26f7670176ecb73f261757134e190fcf5 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 5 Mar 2017 15:18:29 -0600 Subject: [PATCH 65/99] Comment out pr stats experiment. Add JSON doc for issues. --- docs/rest_api/Issues.md | 22 +++++++++++++++++++ repo_health/gh_issues/models/GhIssueEvent.py | 10 +++++++++ .../GhPullRequestStatsSerializer.py | 18 +++++++-------- 3 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 docs/rest_api/Issues.md diff --git a/docs/rest_api/Issues.md b/docs/rest_api/Issues.md new file mode 100644 index 0000000..25fa12f --- /dev/null +++ b/docs/rest_api/Issues.md @@ -0,0 +1,22 @@ +# Issue stats for a repo + +Issue stats are retrieved with the repo id. A GET request is made to the following repo. + + - `/api/v1/gh-projects//issues` + + ``` +issues_opened_past_yr: [int], //Issues opened per month over past year from most recent issue +issues_closed_past_yr: [int], //Issues closed per month over past year from most recent issue +issues_count: int, +merged_count: int, +avg_lifetime: str, +popular_labels: [ //Five most popular labels + label_name: { + total: int, total issues with label + open: int //open issues with label + }, ... +contrib_comments_per_issue: int +] + + +``` \ No newline at end of file diff --git a/repo_health/gh_issues/models/GhIssueEvent.py b/repo_health/gh_issues/models/GhIssueEvent.py index ad465f7..0c9cf37 100644 --- a/repo_health/gh_issues/models/GhIssueEvent.py +++ b/repo_health/gh_issues/models/GhIssueEvent.py @@ -14,6 +14,16 @@ class GhIssueEvent(models.Model): + MERGED_ACTION = 'merged' + OPENED_ACTION = 'opened' + SUBSCRIBED_ACTION = 'subscribed' + REF_ACTION = 'referenced' + CLOSED_ACTION = 'closed' + REOPENED_ACTION = 'reopened' + ASSIGNED_ACTION = 'assigned' + MENTIONED_ACTION = 'mentioned' + DELETED_ACTION = 'head_ref_deleted' + event_id = models.TextField() issue = models.ForeignKey('gh_issues.GhIssue', models.DO_NOTHING) actor = models.ForeignKey('gh_users.GhUser', models.DO_NOTHING) diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 830064d..7407951 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -102,14 +102,14 @@ def get_avg_lifetime(self, repo): avg = (td / closed).days # Save this code to hopefully aggregate the average at the database level sometime. - agg = GhPullRequest.objects.raw( - "SELECT `pull_requests`.`id`, `pull_request_history`.`created_at` as `created_at`, `t`.`created_at` as " + - "`closed_at` from `pull_requests` join `pull_request_history` on `pull_request_history`." + - "`pull_request_id` = `pull_requests`.`id` join `pull_request_history` `t` on`pull_request_history`." + - "`pull_request_id` = `pull_requests`.`id` where `t`.`action` = 'closed' and `pull_request_history`." + - "`action` = 'opened' and `pull_requests`.`base_repo_id` = %s", [repo.id], - - ) + # agg = GhPullRequest.objects.raw( + # "SELECT `pull_requests`.`id`, `pull_request_history`.`created_at` as `created_at`, `t`.`created_at` as " + + # "`closed_at` from `pull_requests` join `pull_request_history` on `pull_request_history`." + + # "`pull_request_id` = `pull_requests`.`id` join `pull_request_history` `t` on`pull_request_history`." + + # "`pull_request_id` = `pull_requests`.`id` where `t`.`action` = 'closed' and `pull_request_history`." + + # "`action` = 'opened' and `pull_requests`.`base_repo_id` = %s", [repo.id], + + # ) # agg = repo.prs_to \ # .annotate(closed_at=m.Case( # m.When( @@ -126,7 +126,7 @@ def get_avg_lifetime(self, repo): # .values('created_at', 'closed_at', 'id', 'history__action') \ # .exclude(m.Q(history__action=GhPullRequestHistory.CLOSED_ACTION) & m.Q(closed_at__isnull=True)).query # .aggregate(avg=m.Avg(m.F('created_at') - m.F('closed_at'), output_field=m.DurationField())) - print(agg) + # print(agg) return avg From d6127e8a932f67bfd72e938f5b547396a08a89cf Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 12 Mar 2017 16:28:20 -0500 Subject: [PATCH 66/99] Files for issue stats. Response includes issues_count. --- docs/rest_api/Issues.md | 2 +- repo_health/gh_issues/models/GhIssue.py | 6 ++++- .../serializers/GhIssueStatsSerializer.py | 27 +++++++++++++++++++ repo_health/gh_issues/serializers/__init__.py | 14 ++++++++++ repo_health/gh_projects/tests.py | 10 ++++--- repo_health/gh_projects/views.py | 10 +++++++ .../GhPullRequestStatsSerializer.py | 9 +++---- 7 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 repo_health/gh_issues/serializers/GhIssueStatsSerializer.py create mode 100644 repo_health/gh_issues/serializers/__init__.py diff --git a/docs/rest_api/Issues.md b/docs/rest_api/Issues.md index 25fa12f..8901c12 100644 --- a/docs/rest_api/Issues.md +++ b/docs/rest_api/Issues.md @@ -12,7 +12,7 @@ merged_count: int, avg_lifetime: str, popular_labels: [ //Five most popular labels label_name: { - total: int, total issues with label + total: int, //total issues with label open: int //open issues with label }, ... contrib_comments_per_issue: int diff --git a/repo_health/gh_issues/models/GhIssue.py b/repo_health/gh_issues/models/GhIssue.py index f0054a2..d227b1b 100644 --- a/repo_health/gh_issues/models/GhIssue.py +++ b/repo_health/gh_issues/models/GhIssue.py @@ -14,7 +14,11 @@ class GhIssue(models.Model): - repo = models.ForeignKey('gh_projects.GhProject', models.DO_NOTHING, blank=True, null=True) + repo = models.ForeignKey('gh_projects.GhProject', models.DO_NOTHING, + blank=True, null=True, + related_name='issues' + ) + reporter = models.ForeignKey( 'gh_users.GhUser', models.DO_NOTHING, blank=True, null=True, related_name='reporter' diff --git a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py new file mode 100644 index 0000000..151aff3 --- /dev/null +++ b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py @@ -0,0 +1,27 @@ +""" +serializers.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Serializer for issue stats of a GitHub repo. +""" + + +from rest_framework import serializers as s + + +class GhIssueStatsSerializer(s.Serializer): + + issues_count = s.SerializerMethodField() + # issues_last_year = s.SerializerMethodField() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.repo = args[0] + + def get_issues_count(self, repo): + return repo.issues_count diff --git a/repo_health/gh_issues/serializers/__init__.py b/repo_health/gh_issues/serializers/__init__.py new file mode 100644 index 0000000..7dd4921 --- /dev/null +++ b/repo_health/gh_issues/serializers/__init__.py @@ -0,0 +1,14 @@ +""" +__init__.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Import all classes from package. +""" + + +from .GhIssueStatsSerializer import GhIssueStatsSerializer \ No newline at end of file diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 59fc217..98104a1 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -110,7 +110,7 @@ def test_api_get_project_not_found(self): def test_get_pr_stats(self): r = self.client.get('/api/v1/gh-projects/%d/pull-requests' % self.django.id) self.assertTrue(status.is_success(r.status_code), 'Status code was: %d' % r.status_code) - # Check for a few custom fields of the serialozer + # Check for a few custom fields of the serializer self.assertTrue(r.data['pr_count'] and isinstance(r.data['pr_count'], int)) self.assertTrue(r.data['prs_last_year'] and isinstance(r.data['prs_last_year'], list)) self.assertTrue( @@ -120,9 +120,11 @@ def test_get_pr_stats(self): self.assertTrue( r.data.get('prs_no_maintainer_comments') and isinstance(r.data['prs_no_maintainer_comments'], int)) - # Test a repo with no prs to be sure no errors are thrown self.client.get('/api/v1/gh-projects/%d/pull-requests' % self.project_no_prs.id) - - + def test_get_issue_stats(self): + r = self.client.get('/api/v1/gh-projects/%d/issues' % self.django.id) + print (r.data) + self.assertTrue(status.is_success(r.status_code)) + self.assertTrue(r.data.get('issues_count')) diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index bf18fa2..d882cb3 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -19,6 +19,7 @@ from rest_framework.response import Response from rest_framework.decorators import detail_route from repo_health.gh_pull_requests.serializers import GhPullRequestStatsSerializer +from repo_health.gh_issues.serializers import GhIssueStatsSerializer from .models import GhProject from .serializers import GhProjectSerializer, StatsUrlsSerializer from repo_health.metrics.serializers import ResponseSerializer @@ -68,3 +69,12 @@ def pull_requests(self, *args, **kwargs): pr_stats = GhPullRequestStatsSerializer(repo) return Response(pr_stats.data) + + @detail_route(methods=['GET']) + def issues(self, *args, **kwargs): + repo = GhProject.objects\ + .annotate(issues_count=models.Count('issues'))\ + .get(pk=kwargs['pk']) + + ser = GhIssueStatsSerializer(repo) + return Response(ser.data) diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 7407951..4f734e2 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -15,7 +15,7 @@ from django.db import models as m from rest_framework import serializers as s from repo_health.gh_users.models import GhUser -from ..models import GhPullRequestHistory, GhPullRequest +from ..models import GhPullRequestHistory class GhPullRequestStatsSerializer(s.Serializer): @@ -142,7 +142,6 @@ def get_prs_from_outside_org(self, repo): if repo.is_owned_by_org(): return repo.prs_to.exclude(user__organizations=repo.owner).count() - class Meta: - model = 'gh_projects.GhProject' - fields = ('pr_count', ) - + # class Meta: + # model = 'gh_projects.GhProject' + # fields = ('pr_count', ) From 5759c37bce39be887efcdf178806b2b3f6fc031b Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 12 Mar 2017 19:02:08 -0500 Subject: [PATCH 67/99] Test a project with issues. --- repo_health/gh_issues/models/GhIssueEvent.py | 7 +++-- .../serializers/GhIssueStatsSerializer.py | 30 +++++++++++++++++-- repo_health/gh_projects/tests.py | 7 +++-- repo_health/gh_projects/views.py | 3 ++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/repo_health/gh_issues/models/GhIssueEvent.py b/repo_health/gh_issues/models/GhIssueEvent.py index 0c9cf37..0d91a4d 100644 --- a/repo_health/gh_issues/models/GhIssueEvent.py +++ b/repo_health/gh_issues/models/GhIssueEvent.py @@ -15,7 +15,7 @@ class GhIssueEvent(models.Model): MERGED_ACTION = 'merged' - OPENED_ACTION = 'opened' + OPENED_ACTION = 'opened' # No opened events in test DB. Issue has created_at field. Assume this is opened datetime SUBSCRIBED_ACTION = 'subscribed' REF_ACTION = 'referenced' CLOSED_ACTION = 'closed' @@ -25,7 +25,9 @@ class GhIssueEvent(models.Model): DELETED_ACTION = 'head_ref_deleted' event_id = models.TextField() - issue = models.ForeignKey('gh_issues.GhIssue', models.DO_NOTHING) + issue = models.ForeignKey( + 'gh_issues.GhIssue', models.DO_NOTHING, related_name='events' + ) actor = models.ForeignKey('gh_users.GhUser', models.DO_NOTHING) action = models.CharField(max_length=255) action_specific = models.CharField(max_length=50, blank=True, null=True) @@ -36,4 +38,3 @@ class Meta: managed = False db_table = 'issue_events' verbose_name = 'GitHub Issue Event' - diff --git a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py index 151aff3..11a331d 100644 --- a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py +++ b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py @@ -10,18 +10,42 @@ Serializer for issue stats of a GitHub repo. """ - +import calendar +import datetime from rest_framework import serializers as s +from ..models import GhIssueEvent class GhIssueStatsSerializer(s.Serializer): + _issues_last_year = None + issues_count = s.SerializerMethodField() - # issues_last_year = s.SerializerMethodField() + issues_closed_last_year = s.SerializerMethodField() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.repo = args[0] + repo = args[0] + one_yr_from_most_recent = repo.most_recent_issue_created - datetime.timedelta(days=366) + self._issues_last_year = repo.issues.filter(created_at__gte=one_yr_from_most_recent) def get_issues_count(self, repo): return repo.issues_count + + def get_issues_closed_last_year(self, repo): + closed = self._issues_last_year.filter( + events__action=GhIssueEvent.CLOSED_ACTION + ).order_by('-events__created_at').distinct() + opened_count_for_year = [] + if closed.exists(): + # Some projects don't have issues in Github + dt_to_filter = closed.last().created_at + for mon in range(12): + days_in_mon = calendar.monthrange(dt_to_filter.year, dt_to_filter.month)[1] + opened_count_for_year.append(closed.filter( + events__created_at__year=dt_to_filter.year, + events__created_at__month=dt_to_filter.month).count()) + dt_to_filter += datetime.timedelta(days=days_in_mon) + else: + opened_count_for_year = [0] * 12 + return opened_count_for_year diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 98104a1..4d4e215 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -67,6 +67,7 @@ def setUp(self): self.project_no_prs = GhProject.objects.annotate(prs_to_count=m.Count('prs_to')).order_by('prs_to_count').first() # Django has a lot of pull requests self.django = GhProject.objects.get(name='django', owner__login='django') + self.project_with_issues = GhProject.objects.filter(issues__isnull=False).first() def test_api_get_project(self): r = self.client.get(dj_reverse('gh-project-detail', args=[self.project.id])) @@ -118,13 +119,15 @@ def test_get_pr_stats(self): ) self.assertTrue(r.data['contrib_most_prs'] and isinstance(r.data['contrib_most_prs'], str)) self.assertTrue( - r.data.get('prs_no_maintainer_comments') and isinstance(r.data['prs_no_maintainer_comments'], int)) + r.data.get('prs_no_maintainer_comments') and isinstance(r.data['prs_no_maintainer_comments'], int) + ) # Test a repo with no prs to be sure no errors are thrown self.client.get('/api/v1/gh-projects/%d/pull-requests' % self.project_no_prs.id) def test_get_issue_stats(self): - r = self.client.get('/api/v1/gh-projects/%d/issues' % self.django.id) + r = self.client.get('/api/v1/gh-projects/%d/issues' % self.project_with_issues.id) print (r.data) self.assertTrue(status.is_success(r.status_code)) self.assertTrue(r.data.get('issues_count')) + self.assertTrue(r.data.get('issues_closed_last_year') and isinstance(r.data['issues_closed_last_year'], list)) diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index d882cb3..d44c7dc 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -74,6 +74,9 @@ def pull_requests(self, *args, **kwargs): def issues(self, *args, **kwargs): repo = GhProject.objects\ .annotate(issues_count=models.Count('issues'))\ + .annotate(most_recent_issue_created=models.Max('issues__created_at'))\ + .prefetch_related('issues')\ + .prefetch_related('labels')\ .get(pk=kwargs['pk']) ser = GhIssueStatsSerializer(repo) From c2102ccc0f956a8b439714f204a6d361d6323eb5 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 12 Mar 2017 21:39:48 -0500 Subject: [PATCH 68/99] Add mixin to get list of count per month for past year of a queryset. --- .../serializers/GhIssueStatsSerializer.py | 32 ++++--------- repo_health/gh_projects/tests.py | 1 + .../index/mixins/CountForPastYearMixin.py | 48 +++++++++++++++++++ repo_health/index/mixins/__init__.py | 13 +++++ 4 files changed, 72 insertions(+), 22 deletions(-) create mode 100644 repo_health/index/mixins/CountForPastYearMixin.py create mode 100644 repo_health/index/mixins/__init__.py diff --git a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py index 11a331d..2814818 100644 --- a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py +++ b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py @@ -10,42 +10,30 @@ Serializer for issue stats of a GitHub repo. """ -import calendar -import datetime from rest_framework import serializers as s from ..models import GhIssueEvent +from repo_health.index.mixins import CountForPastYearMixin -class GhIssueStatsSerializer(s.Serializer): +class GhIssueStatsSerializer(s.Serializer, CountForPastYearMixin): - _issues_last_year = None + _label_names = None issues_count = s.SerializerMethodField() issues_closed_last_year = s.SerializerMethodField() + issues_opened_last_year = s.SerializerMethodField() + merged_count = s.SerializerMethodField() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) repo = args[0] - one_yr_from_most_recent = repo.most_recent_issue_created - datetime.timedelta(days=366) - self._issues_last_year = repo.issues.filter(created_at__gte=one_yr_from_most_recent) + self._label_names = repo.labels.values_list('name', flat=True) def get_issues_count(self, repo): return repo.issues_count def get_issues_closed_last_year(self, repo): - closed = self._issues_last_year.filter( - events__action=GhIssueEvent.CLOSED_ACTION - ).order_by('-events__created_at').distinct() - opened_count_for_year = [] - if closed.exists(): - # Some projects don't have issues in Github - dt_to_filter = closed.last().created_at - for mon in range(12): - days_in_mon = calendar.monthrange(dt_to_filter.year, dt_to_filter.month)[1] - opened_count_for_year.append(closed.filter( - events__created_at__year=dt_to_filter.year, - events__created_at__month=dt_to_filter.month).count()) - dt_to_filter += datetime.timedelta(days=days_in_mon) - else: - opened_count_for_year = [0] * 12 - return opened_count_for_year + return self.get_count_list_for_year(repo.issues.filter(events__action=GhIssueEvent.CLOSED_ACTION).distinct()) + + def get_issues_opened_last_year(self, repo): + return self.get_count_list_for_year(repo.issues) diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 4d4e215..4d67c72 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -111,6 +111,7 @@ def test_api_get_project_not_found(self): def test_get_pr_stats(self): r = self.client.get('/api/v1/gh-projects/%d/pull-requests' % self.django.id) self.assertTrue(status.is_success(r.status_code), 'Status code was: %d' % r.status_code) + print(r.data) # Check for a few custom fields of the serializer self.assertTrue(r.data['pr_count'] and isinstance(r.data['pr_count'], int)) self.assertTrue(r.data['prs_last_year'] and isinstance(r.data['prs_last_year'], list)) diff --git a/repo_health/index/mixins/CountForPastYearMixin.py b/repo_health/index/mixins/CountForPastYearMixin.py new file mode 100644 index 0000000..0e64572 --- /dev/null +++ b/repo_health/index/mixins/CountForPastYearMixin.py @@ -0,0 +1,48 @@ +""" +CountForPastYearMixin.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Provides some utility methods and constants for filtering a queryset for the past year into a list of integers of the +number of occurrences for each month. +""" + + +import datetime +import calendar +from django.db.models import F + + +class CountForPastYearMixin(object): + ONE_YEAR = datetime.timedelta(days=366) + + def get_count_list_for_year(self, queryset, query_string='created_at'): + """ + Builds a list of occurrences per month using the string provided for Django style filtering. + Assume query_string=`created_at` if not supplied. + Will get the most recent occurrence of the queryset based on the query_string and get the previous year's + occurrences from that date. + :param queryset: Django queryset. Members are assumed to have a created_at field + :param query_string: String used with Django style filtering + :return: 12 element list of the number of occurrences per month + """ + + count_for_year = [] + + if queryset.exists(): + most_recent = queryset.order_by(F(query_string).desc()).first().created_at + dt_to_filter = most_recent - self.ONE_YEAR + for mon in range(12): + qwargs = { + query_string + '__year': dt_to_filter.year, + query_string + '__month': dt_to_filter.month + + } + days_in_mon = calendar.monthrange(dt_to_filter.year, dt_to_filter.month)[1] + count_for_year.append(queryset.filter(**qwargs).count()) + dt_to_filter += datetime.timedelta(days=days_in_mon) + return count_for_year diff --git a/repo_health/index/mixins/__init__.py b/repo_health/index/mixins/__init__.py new file mode 100644 index 0000000..479ed2a --- /dev/null +++ b/repo_health/index/mixins/__init__.py @@ -0,0 +1,13 @@ +""" +__init__.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Mixins to be used across packages. Import them here. +""" + +from .CountForPastYearMixin import CountForPastYearMixin \ No newline at end of file From 9a22aadaf9d4d5abbf1fe6c37a8b0215c6f7e976 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sun, 12 Mar 2017 22:14:43 -0500 Subject: [PATCH 69/99] PR stats use the mixin. Add merged count to issue stats. --- .../GhPullRequestStatsSerializer.py | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 4f734e2..3a279e5 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -16,9 +16,10 @@ from rest_framework import serializers as s from repo_health.gh_users.models import GhUser from ..models import GhPullRequestHistory +from repo_health.index.mixins import CountForPastYearMixin -class GhPullRequestStatsSerializer(s.Serializer): +class GhPullRequestStatsSerializer(s.Serializer, CountForPastYearMixin): _most_recent_history = None _opened_histories = None _contrib_most_prs = None @@ -60,20 +61,21 @@ def get_pr_count(self, repo): return repo.pr_count def get_prs_last_year(self, repo): - one_year = datetime.timedelta(days=366) - opened_count_for_year = [] - - if self._most_recent_history: - opened_prev_year = self._opened_histories.filter(created_at__gte=self._most_recent_history.created_at - one_year) - dt_to_filter = opened_prev_year.last().created_at - - for m in range(12): - days_in_mon = calendar.monthrange(dt_to_filter.year, dt_to_filter.month)[1] - opened_count_for_year.append(opened_prev_year.filter( - created_at__year=dt_to_filter.year, - created_at__month=dt_to_filter.month).count()) - dt_to_filter += datetime.timedelta(days=days_in_mon) - return opened_count_for_year + return self.get_count_list_for_year(self._opened_histories, 'created_at') + # one_year = datetime.timedelta(days=366) + # opened_count_for_year = [] + # + # if self._most_recent_history: + # opened_prev_year = self._opened_histories.filter(created_at__gte=self._most_recent_history.created_at - one_year) + # dt_to_filter = opened_prev_year.last().created_at + # + # for m in range(12): + # days_in_mon = calendar.monthrange(dt_to_filter.year, dt_to_filter.month)[1] + # opened_count_for_year.append(opened_prev_year.filter( + # created_at__year=dt_to_filter.year, + # created_at__month=dt_to_filter.month).count()) + # dt_to_filter += datetime.timedelta(days=days_in_mon) + # return opened_count_for_year def get_latest_pr_created_at(self, repo): return self._most_recent_history.created_at if self._most_recent_history else None From a89b6ec1bda46c63c0ff0e0a8bb44eb3eda41c1b Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 13 Mar 2017 21:03:32 -0500 Subject: [PATCH 70/99] Add get merged count method. --- repo_health/gh_issues/serializers/GhIssueStatsSerializer.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py index 2814818..1b1ae0b 100644 --- a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py +++ b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py @@ -37,3 +37,6 @@ def get_issues_closed_last_year(self, repo): def get_issues_opened_last_year(self, repo): return self.get_count_list_for_year(repo.issues) + + def get_merged_count(self, repo): + return repo.issues.filter(events__action=GhIssueEvent.MERGED_ACTION).count() From 91a050d360a12e7db434f5580350da90d6c546dc Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sat, 18 Mar 2017 12:20:52 -0500 Subject: [PATCH 71/99] Add average lifetime and popular labels to issue stats. --- repo_health/gh_issues/models/GhIssue.py | 2 +- repo_health/gh_issues/models/GhIssueEvent.py | 2 +- .../serializers/GhIssueStatsSerializer.py | 31 +++++++++++++++++++ .../TotalAndOpenIssueLabelSerial.py | 28 +++++++++++++++++ repo_health/gh_issues/serializers/__init__.py | 3 +- .../serializers/GhProjectSerializer.py | 2 +- repo_health/gh_projects/views.py | 1 + .../GhPullRequestStatsSerializer.py | 14 --------- 8 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 repo_health/gh_issues/serializers/TotalAndOpenIssueLabelSerial.py diff --git a/repo_health/gh_issues/models/GhIssue.py b/repo_health/gh_issues/models/GhIssue.py index d227b1b..1036e0d 100644 --- a/repo_health/gh_issues/models/GhIssue.py +++ b/repo_health/gh_issues/models/GhIssue.py @@ -47,7 +47,7 @@ class GhIssue(models.Model): labels = models.ManyToManyField( 'gh_projects.GhRepoLabel', - through='gh_issues.GhIssueLabel' + through='gh_issues.GhIssueLabel', related_name='issues' ) def __str__(self): diff --git a/repo_health/gh_issues/models/GhIssueEvent.py b/repo_health/gh_issues/models/GhIssueEvent.py index 0d91a4d..9c2631c 100644 --- a/repo_health/gh_issues/models/GhIssueEvent.py +++ b/repo_health/gh_issues/models/GhIssueEvent.py @@ -24,7 +24,7 @@ class GhIssueEvent(models.Model): MENTIONED_ACTION = 'mentioned' DELETED_ACTION = 'head_ref_deleted' - event_id = models.TextField() + event_id = models.TextField(primary_key=True) issue = models.ForeignKey( 'gh_issues.GhIssue', models.DO_NOTHING, related_name='events' ) diff --git a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py index 1b1ae0b..3b334e1 100644 --- a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py +++ b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py @@ -10,8 +10,11 @@ Serializer for issue stats of a GitHub repo. """ +import datetime from rest_framework import serializers as s from ..models import GhIssueEvent +from .TotalAndOpenIssueLabelSerial import TotalAndOpenIssueLabelSerial +from repo_health.gh_projects.models import GhRepoLabel from repo_health.index.mixins import CountForPastYearMixin @@ -23,6 +26,8 @@ class GhIssueStatsSerializer(s.Serializer, CountForPastYearMixin): issues_closed_last_year = s.SerializerMethodField() issues_opened_last_year = s.SerializerMethodField() merged_count = s.SerializerMethodField() + avg_lifetime = s.SerializerMethodField() + popular_labels = s.SerializerMethodField() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -40,3 +45,29 @@ def get_issues_opened_last_year(self, repo): def get_merged_count(self, repo): return repo.issues.filter(events__action=GhIssueEvent.MERGED_ACTION).count() + + def get_avg_lifetime(self, repo): + # Similar inefficiency as the PR stats but must access the fields a little differently. + avg = closed = 0 + if repo.issues_count is not 0: + td = datetime.timedelta() + closed_issues = repo.issues.prefetch_related('events').filter(events__action=GhIssueEvent.CLOSED_ACTION) + for i in closed_issues.all(): + closed += 1 + close_event = i.events.filter(action=GhIssueEvent.CLOSED_ACTION).order_by('-created_at').first() + td += (close_event.created_at - i.created_at) + avg = (td / closed).days + return avg + + def get_popular_labels(self, repo): + # Raw SQL. + labels_by_count_for_repo = GhRepoLabel.objects.raw( + 'SELECT t.*, count(t.id) as repos_labels FROM repo_labels t join issue_labels il on il.label_id=t.id\ + where t.repo_id = %d GROUP BY t.id ORDER BY repos_labels desc;' % repo.id) + + top_five = labels_by_count_for_repo[:5] + response_data = [] + for l in top_five: + label_serial = TotalAndOpenIssueLabelSerial(l) + response_data.append(label_serial.data) + return response_data \ No newline at end of file diff --git a/repo_health/gh_issues/serializers/TotalAndOpenIssueLabelSerial.py b/repo_health/gh_issues/serializers/TotalAndOpenIssueLabelSerial.py new file mode 100644 index 0000000..6931214 --- /dev/null +++ b/repo_health/gh_issues/serializers/TotalAndOpenIssueLabelSerial.py @@ -0,0 +1,28 @@ +""" +TotalAndOpenLabelSerial.py - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + J. Harding + +Serializer for labels to provide the total issues of the label and the issues open with the label. +""" + +from rest_framework import serializers as s +from ..models import GhIssueEvent + + +class TotalAndOpenIssueLabelSerial(s.Serializer): + total = s.SerializerMethodField() + open = s.SerializerMethodField() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def get_total(self, label): + return label.issues.count() + + def get_open(self, label): + return label.issues.exclude(events__action=GhIssueEvent.CLOSED_ACTION).count() diff --git a/repo_health/gh_issues/serializers/__init__.py b/repo_health/gh_issues/serializers/__init__.py index 7dd4921..fb38ee9 100644 --- a/repo_health/gh_issues/serializers/__init__.py +++ b/repo_health/gh_issues/serializers/__init__.py @@ -11,4 +11,5 @@ """ -from .GhIssueStatsSerializer import GhIssueStatsSerializer \ No newline at end of file +from .GhIssueStatsSerializer import GhIssueStatsSerializer +from .TotalAndOpenIssueLabelSerial import TotalAndOpenIssueLabelSerial diff --git a/repo_health/gh_projects/serializers/GhProjectSerializer.py b/repo_health/gh_projects/serializers/GhProjectSerializer.py index 8ae3c93..c44fd31 100644 --- a/repo_health/gh_projects/serializers/GhProjectSerializer.py +++ b/repo_health/gh_projects/serializers/GhProjectSerializer.py @@ -1,5 +1,5 @@ """ -serializers.py - (C) Copyright - 2017 +GhProjectSerializer.py - (C) Copyright - 2017 This software is copyrighted to contributors listed in CONTRIBUTIONS.md. SPDX-License-Identifier: MIT diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index d44c7dc..ead5158 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -75,6 +75,7 @@ def issues(self, *args, **kwargs): repo = GhProject.objects\ .annotate(issues_count=models.Count('issues'))\ .annotate(most_recent_issue_created=models.Max('issues__created_at'))\ + .annotate(labels_count=models.Count('labels'))\ .prefetch_related('issues')\ .prefetch_related('labels')\ .get(pk=kwargs['pk']) diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 3a279e5..d71ab2f 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -62,20 +62,6 @@ def get_pr_count(self, repo): def get_prs_last_year(self, repo): return self.get_count_list_for_year(self._opened_histories, 'created_at') - # one_year = datetime.timedelta(days=366) - # opened_count_for_year = [] - # - # if self._most_recent_history: - # opened_prev_year = self._opened_histories.filter(created_at__gte=self._most_recent_history.created_at - one_year) - # dt_to_filter = opened_prev_year.last().created_at - # - # for m in range(12): - # days_in_mon = calendar.monthrange(dt_to_filter.year, dt_to_filter.month)[1] - # opened_count_for_year.append(opened_prev_year.filter( - # created_at__year=dt_to_filter.year, - # created_at__month=dt_to_filter.month).count()) - # dt_to_filter += datetime.timedelta(days=days_in_mon) - # return opened_count_for_year def get_latest_pr_created_at(self, repo): return self._most_recent_history.created_at if self._most_recent_history else None From 12b08ebb703e03f9aed68f71901412680c5127af Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sat, 18 Mar 2017 14:52:25 -0500 Subject: [PATCH 72/99] Add average maintainer comments per issue. --- README.md | 10 ++++++++ docs/rest_api/Issues.md | 2 +- repo_health/gh_issues/models/GhIssue.py | 6 ++--- .../serializers/GhIssueStatsSerializer.py | 23 ++++++++++++++----- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 4995e63..f0729b1 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,16 @@ A Linux production environment is recommmended, and Ubuntu version 12 and greate ## Database configuration Both production and development environments use MySql for a DBMS and require a database configuration specific to the individual environment. +If using mysql 5.7 or greater, a warning may been seen due to strict mode being enable by default. Turn off strict mode by adding a file named: + +`/usr/local/bin/etc/my.cnf`. + +To this file add: +``` +[mysqld] + +sql_mode=NO_ENGINE_SUBSTITUTION +``` #### Development For development, a subset of data is used for testing and provided by ghtorrent [here](http://ghtorrent.org/msr14.html). Use this link to download the database, and after successful download, unpack the archive to your desired location. Take note of the location. The supplied data requires a database to hold so we need to create one using MySql. The installation of MySql varies on the package manager being used, so it is assumed MySql is installed and running. diff --git a/docs/rest_api/Issues.md b/docs/rest_api/Issues.md index 8901c12..cacdf32 100644 --- a/docs/rest_api/Issues.md +++ b/docs/rest_api/Issues.md @@ -15,7 +15,7 @@ popular_labels: [ //Five most popular labels total: int, //total issues with label open: int //open issues with label }, ... -contrib_comments_per_issue: int +avg_maintainer_comments_per_issue: int ] diff --git a/repo_health/gh_issues/models/GhIssue.py b/repo_health/gh_issues/models/GhIssue.py index 1036e0d..112f980 100644 --- a/repo_health/gh_issues/models/GhIssue.py +++ b/repo_health/gh_issues/models/GhIssue.py @@ -38,7 +38,7 @@ class GhIssue(models.Model): created_at = models.DateTimeField() ext_ref_id = models.CharField(max_length=24) - #M2M fields add + # M2M fields add comment_users = models.ManyToManyField( 'gh_users.GhUser', through='gh_issues.GhIssueComment', @@ -47,11 +47,11 @@ class GhIssue(models.Model): labels = models.ManyToManyField( 'gh_projects.GhRepoLabel', - through='gh_issues.GhIssueLabel', related_name='issues' + through='gh_issues.GhIssueLabel', related_name='label_issues' ) def __str__(self): - return "Issue for: %s" %self.repo.name + return "Issue for: %s" % self.repo.name class Meta: managed = False diff --git a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py index 3b334e1..8845657 100644 --- a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py +++ b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py @@ -11,8 +11,9 @@ """ import datetime +from django.db import models as m from rest_framework import serializers as s -from ..models import GhIssueEvent +from ..models import GhIssueEvent, GhIssueComment from .TotalAndOpenIssueLabelSerial import TotalAndOpenIssueLabelSerial from repo_health.gh_projects.models import GhRepoLabel from repo_health.index.mixins import CountForPastYearMixin @@ -28,11 +29,11 @@ class GhIssueStatsSerializer(s.Serializer, CountForPastYearMixin): merged_count = s.SerializerMethodField() avg_lifetime = s.SerializerMethodField() popular_labels = s.SerializerMethodField() + avg_maintainer_comments_per_issue = s.SerializerMethodField() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) repo = args[0] - self._label_names = repo.labels.values_list('name', flat=True) def get_issues_count(self, repo): return repo.issues_count @@ -51,12 +52,15 @@ def get_avg_lifetime(self, repo): avg = closed = 0 if repo.issues_count is not 0: td = datetime.timedelta() - closed_issues = repo.issues.prefetch_related('events').filter(events__action=GhIssueEvent.CLOSED_ACTION) + closed_issues = repo.issues.prefetch_related('events').filter(events__action=GhIssueEvent.CLOSED_ACTION, + created_at__isnull=False) + for i in closed_issues.all(): closed += 1 close_event = i.events.filter(action=GhIssueEvent.CLOSED_ACTION).order_by('-created_at').first() - td += (close_event.created_at - i.created_at) - avg = (td / closed).days + if not isinstance(i.created_at, type(None)): + td += (close_event.created_at - i.created_at) + avg = (td / closed).days if closed > 0 else closed return avg def get_popular_labels(self, repo): @@ -70,4 +74,11 @@ def get_popular_labels(self, repo): for l in top_five: label_serial = TotalAndOpenIssueLabelSerial(l) response_data.append(label_serial.data) - return response_data \ No newline at end of file + return response_data + + def get_avg_maintainer_comments_per_issue(self, repo): + comments_from_m = GhIssueComment.objects.filter( + issue__in=repo.issues.all(), + user__in=repo.maintainers.all() + ).count() + return comments_from_m / repo.issues.count() \ No newline at end of file From d0ce26b4cf538d047fa9c4afa18112a7c446945b Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Sat, 18 Mar 2017 15:01:06 -0500 Subject: [PATCH 73/99] Some code clean up. --- repo_health/gh_issues/models/GhIssueEvent.py | 2 +- .../gh_issues/serializers/GhIssueStatsSerializer.py | 9 +-------- .../serializers/TotalAndOpenIssueLabelSerial.py | 3 --- .../serializers/GhPullRequestStatsSerializer.py | 4 ---- 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/repo_health/gh_issues/models/GhIssueEvent.py b/repo_health/gh_issues/models/GhIssueEvent.py index 9c2631c..5ceb71e 100644 --- a/repo_health/gh_issues/models/GhIssueEvent.py +++ b/repo_health/gh_issues/models/GhIssueEvent.py @@ -15,7 +15,7 @@ class GhIssueEvent(models.Model): MERGED_ACTION = 'merged' - OPENED_ACTION = 'opened' # No opened events in test DB. Issue has created_at field. Assume this is opened datetime + OPENED_ACTION = 'opened' # No opened events in test DB. Issue has created_at field. SUBSCRIBED_ACTION = 'subscribed' REF_ACTION = 'referenced' CLOSED_ACTION = 'closed' diff --git a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py index 8845657..f15b02d 100644 --- a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py +++ b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py @@ -1,5 +1,5 @@ """ -serializers.py - (C) Copyright - 2017 +GhIssueStatsSerializer.py - (C) Copyright - 2017 This software is copyrighted to contributors listed in CONTRIBUTIONS.md. SPDX-License-Identifier: MIT @@ -11,7 +11,6 @@ """ import datetime -from django.db import models as m from rest_framework import serializers as s from ..models import GhIssueEvent, GhIssueComment from .TotalAndOpenIssueLabelSerial import TotalAndOpenIssueLabelSerial @@ -21,8 +20,6 @@ class GhIssueStatsSerializer(s.Serializer, CountForPastYearMixin): - _label_names = None - issues_count = s.SerializerMethodField() issues_closed_last_year = s.SerializerMethodField() issues_opened_last_year = s.SerializerMethodField() @@ -31,10 +28,6 @@ class GhIssueStatsSerializer(s.Serializer, CountForPastYearMixin): popular_labels = s.SerializerMethodField() avg_maintainer_comments_per_issue = s.SerializerMethodField() - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - repo = args[0] - def get_issues_count(self, repo): return repo.issues_count diff --git a/repo_health/gh_issues/serializers/TotalAndOpenIssueLabelSerial.py b/repo_health/gh_issues/serializers/TotalAndOpenIssueLabelSerial.py index 6931214..768e26b 100644 --- a/repo_health/gh_issues/serializers/TotalAndOpenIssueLabelSerial.py +++ b/repo_health/gh_issues/serializers/TotalAndOpenIssueLabelSerial.py @@ -18,9 +18,6 @@ class TotalAndOpenIssueLabelSerial(s.Serializer): total = s.SerializerMethodField() open = s.SerializerMethodField() - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - def get_total(self, label): return label.issues.count() diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index d71ab2f..88849b9 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -129,7 +129,3 @@ def get_avg_comment_per_pr(self, repo): def get_prs_from_outside_org(self, repo): if repo.is_owned_by_org(): return repo.prs_to.exclude(user__organizations=repo.owner).count() - - # class Meta: - # model = 'gh_projects.GhProject' - # fields = ('pr_count', ) From 357a699bbceb7613d576c6e4ab3c0c4af1788f9f Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Thu, 23 Mar 2017 17:49:14 -0500 Subject: [PATCH 74/99] Change pr and issue serializer to use common response. --- repo_health/gh_projects/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/repo_health/gh_projects/views.py b/repo_health/gh_projects/views.py index ead5158..619b3aa 100644 --- a/repo_health/gh_projects/views.py +++ b/repo_health/gh_projects/views.py @@ -68,7 +68,8 @@ def pull_requests(self, *args, **kwargs): .get(pk=kwargs['pk']) pr_stats = GhPullRequestStatsSerializer(repo) - return Response(pr_stats.data) + resp = ResponseSerializer(pr_stats.data) + return Response(resp.data) @detail_route(methods=['GET']) def issues(self, *args, **kwargs): @@ -81,4 +82,5 @@ def issues(self, *args, **kwargs): .get(pk=kwargs['pk']) ser = GhIssueStatsSerializer(repo) - return Response(ser.data) + resp = ResponseSerializer(ser.data) + return Response(resp.data) From 4805c69abc18e2ebd09849b35f3f34da74559f84 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Thu, 23 Mar 2017 17:49:44 -0500 Subject: [PATCH 75/99] Change pr and issue serializer to use common response. Rest of files. --- .../serializers/GhIssueStatsSerializer.py | 22 ++++++++---- repo_health/gh_projects/tests.py | 17 +++------ .../GhPullRequestStatsSerializer.py | 35 ++++++++++++------- .../metrics/serializers/ResponseSerializer.py | 2 +- 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py index f15b02d..9332c4e 100644 --- a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py +++ b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py @@ -16,29 +16,37 @@ from .TotalAndOpenIssueLabelSerial import TotalAndOpenIssueLabelSerial from repo_health.gh_projects.models import GhRepoLabel from repo_health.index.mixins import CountForPastYearMixin +from repo_health.metrics.serializers import MetricField class GhIssueStatsSerializer(s.Serializer, CountForPastYearMixin): + card_title = s.SerializerMethodField() issues_count = s.SerializerMethodField() issues_closed_last_year = s.SerializerMethodField() issues_opened_last_year = s.SerializerMethodField() merged_count = s.SerializerMethodField() avg_lifetime = s.SerializerMethodField() - popular_labels = s.SerializerMethodField() + # popular_labels = s.SerializerMethodField() avg_maintainer_comments_per_issue = s.SerializerMethodField() + def get_card_title(self, repo): + return MetricField(True, None, 0, None, "Issues") + def get_issues_count(self, repo): - return repo.issues_count + return MetricField(True, "Number of issues", 1, None, repo.issues_count) def get_issues_closed_last_year(self, repo): - return self.get_count_list_for_year(repo.issues.filter(events__action=GhIssueEvent.CLOSED_ACTION).distinct()) + metric = self.get_count_list_for_year(repo.issues.filter(events__action=GhIssueEvent.CLOSED_ACTION).distinct()) + return MetricField(True, "Closed issues last year", 2, None, metric) def get_issues_opened_last_year(self, repo): - return self.get_count_list_for_year(repo.issues) + metric = self.get_count_list_for_year(repo.issues) + return MetricField(True, "Open issues last year", 3, None, metric) def get_merged_count(self, repo): - return repo.issues.filter(events__action=GhIssueEvent.MERGED_ACTION).count() + merged_count = repo.issues.filter(events__action=GhIssueEvent.MERGED_ACTION).count() + return MetricField(True, "Merged issues", 4, None, merged_count) def get_avg_lifetime(self, repo): # Similar inefficiency as the PR stats but must access the fields a little differently. @@ -54,7 +62,7 @@ def get_avg_lifetime(self, repo): if not isinstance(i.created_at, type(None)): td += (close_event.created_at - i.created_at) avg = (td / closed).days if closed > 0 else closed - return avg + return MetricField(True, "Average issue lifetime", 5, 'date', avg) def get_popular_labels(self, repo): # Raw SQL. @@ -74,4 +82,4 @@ def get_avg_maintainer_comments_per_issue(self, repo): issue__in=repo.issues.all(), user__in=repo.maintainers.all() ).count() - return comments_from_m / repo.issues.count() \ No newline at end of file + return MetricField(True, 'Average maintainer comments per issue', 6, None, comments_from_m / repo.issues.count()) \ No newline at end of file diff --git a/repo_health/gh_projects/tests.py b/repo_health/gh_projects/tests.py index 4d67c72..b25bae9 100644 --- a/repo_health/gh_projects/tests.py +++ b/repo_health/gh_projects/tests.py @@ -74,7 +74,7 @@ def test_api_get_project(self): print(r.data) self.assertTrue(status.is_success(r.status_code)) self.assertTrue(isinstance(r.data.get('metrics'), list)) - self.assertTrue(isinstance(r.data.get('charts'), list) and len(r.data['charts']) is 0) + self.assertTrue(isinstance(r.data.get('charts'), dict)) #test with bad input max_id = GhProject.objects.all().aggregate(m.Max('id')).get('id__max') @@ -113,15 +113,8 @@ def test_get_pr_stats(self): self.assertTrue(status.is_success(r.status_code), 'Status code was: %d' % r.status_code) print(r.data) # Check for a few custom fields of the serializer - self.assertTrue(r.data['pr_count'] and isinstance(r.data['pr_count'], int)) - self.assertTrue(r.data['prs_last_year'] and isinstance(r.data['prs_last_year'], list)) - self.assertTrue( - r.data.get('latest_pr_created_at') and isinstance(r.data['latest_pr_created_at'], datetime.datetime) - ) - self.assertTrue(r.data['contrib_most_prs'] and isinstance(r.data['contrib_most_prs'], str)) - self.assertTrue( - r.data.get('prs_no_maintainer_comments') and isinstance(r.data['prs_no_maintainer_comments'], int) - ) + self.assertTrue(r.data.get('metrics') and isinstance(r.data['metrics'], list)) + self.assertTrue(isinstance(r.data['charts'], dict)) # Test a repo with no prs to be sure no errors are thrown self.client.get('/api/v1/gh-projects/%d/pull-requests' % self.project_no_prs.id) @@ -130,5 +123,5 @@ def test_get_issue_stats(self): r = self.client.get('/api/v1/gh-projects/%d/issues' % self.project_with_issues.id) print (r.data) self.assertTrue(status.is_success(r.status_code)) - self.assertTrue(r.data.get('issues_count')) - self.assertTrue(r.data.get('issues_closed_last_year') and isinstance(r.data['issues_closed_last_year'], list)) + self.assertTrue(r.data.get('metrics') and isinstance(r.data['metrics'], list)) + self.assertTrue(isinstance(r.data['charts'], dict)) diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 88849b9..9c18eed 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -11,12 +11,12 @@ """ import datetime -import calendar from django.db import models as m from rest_framework import serializers as s from repo_health.gh_users.models import GhUser from ..models import GhPullRequestHistory from repo_health.index.mixins import CountForPastYearMixin +from repo_health.metrics.serializers import MetricField class GhPullRequestStatsSerializer(s.Serializer, CountForPastYearMixin): @@ -57,26 +57,34 @@ def __init__(self, *args, **kwargs): self._maintainers = repo.maintainers.all() + def get_card_title(self, repo): + return MetricField(True, None, 0, None, 'Pull requests') + def get_pr_count(self, repo): - return repo.pr_count + return MetricField(True, 'Number of pull requests', 1, None, repo.pr_count) def get_prs_last_year(self, repo): - return self.get_count_list_for_year(self._opened_histories, 'created_at') + num_prs = self.get_count_list_for_year(self._opened_histories, 'created_at') + return MetricField(True, 'PRS last year', 2, None, num_prs) def get_latest_pr_created_at(self, repo): - return self._most_recent_history.created_at if self._most_recent_history else None + latest = self._most_recent_history.created_at if self._most_recent_history else None + return MetricField(True, 'Latest pull request created at', 3, None, latest) def get_contrib_most_prs(self, repo): - return self._contrib_most_prs.login if self._contrib_most_prs else None + contrib = self._contrib_most_prs.login if self._contrib_most_prs else None + return MetricField(True, 'Most contributing user', 4, None, contrib) def get_prs_no_maintainer_comments(self, repo): - return repo.prs_to.exclude(comment_users__in=self._maintainers).count() + no_coms = repo.prs_to.exclude(comment_users__in=self._maintainers).count() + return MetricField(True, "PRs with no maintainer comments", 5, None, no_coms) def get_maintainers_count(self, repo): - return self._maintainers.count() + return MetricField(True, 'Number of maintainers', 6, None, self._maintainers.count()) def get_prs_no_comments(self, repo): - return repo.prs_to.annotate(comments_count=m.Count('comments')).filter(comments_count=0).count() + zero_coms = repo.prs_to.annotate(comments_count=m.Count('comments')).filter(comments_count=0).count() + return MetricField(True, 'PRs with zero comments', 7, None, zero_coms) def get_avg_lifetime(self, repo): avg = closed = 0 @@ -116,16 +124,19 @@ def get_avg_lifetime(self, repo): # .aggregate(avg=m.Avg(m.F('created_at') - m.F('closed_at'), output_field=m.DurationField())) # print(agg) - return avg + return MetricField(True, 'Average lifetime', 8, None, avg) def get_not_maintainer_prs(self, repo): - return repo.prs_to.exclude(user__in=self._maintainers).count() + prs_not_main = repo.prs_to.exclude(user__in=self._maintainers).count() + return MetricField(True, 'PRs not from maintainer', 9, None, prs_not_main) def get_avg_comment_per_pr(self, repo): avg_agg = repo.prs_to.annotate(comment_count=m.Count('comments')) \ .aggregate(avg=m.Avg('comment_count')) - return avg_agg['avg'] + return MetricField(True, 'Avg comments per PR', 10, None, avg_agg['avg']) def get_prs_from_outside_org(self, repo): + out_org = None if repo.is_owned_by_org(): - return repo.prs_to.exclude(user__organizations=repo.owner).count() + out_org = repo.prs_to.exclude(user__organizations=repo.owner).count() + return MetricField(True, 'PRs from outside org', 11, None, out_org) diff --git a/repo_health/metrics/serializers/ResponseSerializer.py b/repo_health/metrics/serializers/ResponseSerializer.py index 19b9786..c5c7bcb 100644 --- a/repo_health/metrics/serializers/ResponseSerializer.py +++ b/repo_health/metrics/serializers/ResponseSerializer.py @@ -30,7 +30,7 @@ def __init__(self, repo_data_dict): # TODO Implement charts in response def get_charts(self, obj): - return [] + return {} def get_metrics(self, obj): return self._metrics From eb05407f091a2c578221b4db5384dfc2b9004467 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Thu, 23 Mar 2017 19:40:02 -0500 Subject: [PATCH 76/99] Displaying pr stats. --- .../src/components/repo-details/repo-details.spec.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index ad17e83..0af2e96 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -40,15 +40,20 @@ describe('Repo Details', () => { beforeEach(inject(($injector) => { $componentController = $injector.get('$componentController'); - controller = $componentController('repoDetails', null, { detailsUrl: getDetailsUrl}); - $httpBackend.when('GET', getDetailsUrl).respond(200, {name: 'cakephp', watchers: 15}); + controller = $componentController('repoDetails', null, { detailsUrl: getDetailsUrl, stats: []}); + $httpBackend.when('GET', getDetailsUrl).respond(200, { + metrics: [{ + ordering: 1 + },{ + ordering: 2 + }] + }); })); describe('constructor', () => { it('should setup the controller', () => { expect(controller).toBeDefined(); expect(controller.loadingStats).toBeTruthy(); - expect(controller.stats).toBeNull(); }); it('should request the details in the $onInit method', () => { From a137427477b311f875550e6ff4d0f55950824678 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Thu, 23 Mar 2017 19:40:28 -0500 Subject: [PATCH 77/99] Displaying pr stats. Rest of files. --- .../serializers/GhProjectSerializer.py | 1 - .../GhPullRequestStatsSerializer.py | 1 + .../base-component/base-stats.component.js | 40 +++++++++++++++++++ .../base-component/base-stats.controller.js | 4 +- .../base-component/base.template.html | 5 ++- .../pull-req-stats.component.js | 12 ++++-- .../repo-details/repo-details.component.js | 25 +++--------- 7 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 repo_health/index/static/client/src/components/base-component/base-stats.component.js diff --git a/repo_health/gh_projects/serializers/GhProjectSerializer.py b/repo_health/gh_projects/serializers/GhProjectSerializer.py index c44fd31..79f0fa8 100644 --- a/repo_health/gh_projects/serializers/GhProjectSerializer.py +++ b/repo_health/gh_projects/serializers/GhProjectSerializer.py @@ -45,7 +45,6 @@ class GhProjectSerializer(Serializer): owned_by_org = SerializerMethodField() forks_count = SerializerMethodField() - def __init__(self, *args, **kwargs): """ Get some statistics for repo. diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 9c18eed..2103cab 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -26,6 +26,7 @@ class GhPullRequestStatsSerializer(s.Serializer, CountForPastYearMixin): _maintainers = None _maintainers_count = None + card_title = s.SerializerMethodField() pr_count = s.SerializerMethodField() prs_last_year = s.SerializerMethodField() latest_pr_created_at = s.SerializerMethodField() diff --git a/repo_health/index/static/client/src/components/base-component/base-stats.component.js b/repo_health/index/static/client/src/components/base-component/base-stats.component.js new file mode 100644 index 0000000..174ab4e --- /dev/null +++ b/repo_health/index/static/client/src/components/base-component/base-stats.component.js @@ -0,0 +1,40 @@ +/* +* base-stats.component.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* This is the base controller for the components to hold some commone methods. +*/ + +/** + * Tracks constants for chart names. + */ +const chartNameEnum = { + dateChart: 'date' // Track date as a chart to tell what metrics are dates +} + +export default class BaseStatsComponent { + + stats = []; + + constructor ( $filter ) { + Object.assign( this, {$filter} ) + } + /** + * @description Returns the raw data for the metric based on the chart name + * @param ind + * @returns {*|string} + */ + getRawDataForChartName(ind) { + let rawData = this.stats[ind].raw_data; + switch ( this.stats[ind].chart_name ) { + case chartNameEnum.dateChart: + rawData = this.$filter('date')(rawData); + break; + } + return rawData || 'No'; + }} \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/base-component/base-stats.controller.js b/repo_health/index/static/client/src/components/base-component/base-stats.controller.js index a78d440..5305bc9 100644 --- a/repo_health/index/static/client/src/components/base-component/base-stats.controller.js +++ b/repo_health/index/static/client/src/components/base-component/base-stats.controller.js @@ -7,7 +7,7 @@ * Author(s) of this file: * J.Harding * -* Base stats controller to handle an error state if no repos are return for an owner login and name request +* Base stats controller to handle an error state if no repos are returned for an owner login and name request */ @@ -18,6 +18,4 @@ export default class BaseStatsController { $state.go('search', {error:true}); } } - - } diff --git a/repo_health/index/static/client/src/components/base-component/base.template.html b/repo_health/index/static/client/src/components/base-component/base.template.html index 336606d..8ee0182 100644 --- a/repo_health/index/static/client/src/components/base-component/base.template.html +++ b/repo_health/index/static/client/src/components/base-component/base.template.html @@ -12,7 +12,10 @@ {{ $ctrl.stats[2 * i].raw_data }} - {{ $ctrl.stats[2 * i + 1].raw_data }} + + {{ $ctrl.stats[2 * i + 1].display_name }} + {{ $ctrl.stats[2 * i + 1].raw_data }} + diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index 9cca8ed..4ae27a6 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -11,14 +11,16 @@ */ import template from '../base-component/base.template'; +import BaseStatsComponent from '../base-component/base-stats.component'; const pullReqStatsComponent = { template, bindings: {prStatsUrl: '='}, - controller: class pullReqStatsComponent { + controller: class pullReqStatsComponent extends BaseStatsComponent { stats = null; loadingStats = true; - loadingMsg = "Loading issue stats..."; + loadingMsg = "Loading pull request stats..."; + numOfStatsSections = 0; labels = ['Jan', 'feb', 'Mar', 'April', 'May', 'Jun', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; series = ['Series A', 'Series B']; @@ -57,7 +59,8 @@ const pullReqStatsComponent = { } }; - constructor( $http) { + constructor( $http, $filter ) { + super($filter); 'ngInject'; Object.assign(this, { $http }); } @@ -65,7 +68,8 @@ const pullReqStatsComponent = { $onInit() { if (this.prStatsUrl) { this.$http.get(this.prStatsUrl).then(stats => { - this.stats = stats.data; + this.stats = this.$filter('orderBy')(stats.data.metrics, 'ordering'); + this.numOfStatsSections = new Array(Math.floor(this.stats.length / 2)).fill().map((x,i) => {return i}); this.loadingStats = false; }); } diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index 7fc763a..e465186 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -11,18 +11,12 @@ */ import template from '../base-component/base.template'; - -/** - * Tracks constants for chart names. - */ -const chartNameEnum = { - dateChart: 'date' // Track date as a chart to tell what metrics are dates -} +import BaseStatsComponent from '../base-component/base-stats.component'; const repoDetailsComponent = { template, bindings: {detailsUrl: '='}, - controller: class repoDetailsComponent { + controller: class repoDetailsComponent extends BaseStatsComponent { loadingStats = true; loadingMsg = "Loading general repo stats..."; @@ -30,29 +24,20 @@ const repoDetailsComponent = { numOfStatsSections = 0; constructor($http, $filter) { + super( $filter ); 'ngInject'; - Object.assign(this, { $http, $filter }); + Object.assign(this, { $http }); } $onInit() { if (this.detailsUrl) { this.$http.get(this.detailsUrl).then(details => { this.stats = this.$filter('orderBy')(details.data.metrics, 'ordering'); - this.numOfStatsSections = new Array(this.stats.length / 2).fill().map((x,i)=>i); + this.numOfStatsSections = new Array(this.stats.length / 2).fill().map((x,i) => {return i}); this.loadingStats = false; }); } } - - getRawDataForChartName(ind) { - let rawData = this.stats[ind].raw_data; - switch ( this.stats[ind].chart_name ) { - case chartNameEnum.dateChart: - rawData = this.$filter('date')(rawData); - break; - } - return rawData || 'No'; - } } }; From 171fb596002a0e89e12942468c62b4910f678ca0 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Thu, 23 Mar 2017 22:32:19 -0500 Subject: [PATCH 78/99] Displaying issue stats. Revert to chrome for karma test because phantom doesn't support array.fill. --- .../serializers/GhIssueStatsSerializer.py | 5 +- .../serializers/StatsUrlSerializer.py | 2 +- .../GhPullRequestStatsSerializer.py | 2 +- .../base-component/base-stats.component.js | 17 ++++-- .../base-component/base.template.html | 12 +++- .../src/components/components.module.js | 4 +- .../issue-stats/issue-stats.component.js | 45 ++++++++++++++ .../issue-stats/issue-stats.controller.js | 22 +++++++ .../issue-stats/issue-stats.module.js | 20 +++++++ .../issue-stats/issue-stats.spec.js | 59 +++++++++++++++++++ .../pull-req-stats.component.js | 8 +-- .../pull-req-stats.controller.js | 22 +++++++ .../pull-req-stats/pull-req-stats.spec.js | 11 +++- .../repo-details/repo-details.component.js | 8 +-- .../components/repo-details/repo-details.html | 35 ----------- .../repo-details/repo-details.spec.js | 2 + .../index/static/client/src/main.component.js | 1 + .../index/static/client/src/main.module.js | 16 +++-- repo_health/index/static/karma.conf.js | 4 +- repo_health/index/static/package.json | 1 + 20 files changed, 228 insertions(+), 68 deletions(-) create mode 100644 repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js create mode 100644 repo_health/index/static/client/src/components/issue-stats/issue-stats.controller.js create mode 100644 repo_health/index/static/client/src/components/issue-stats/issue-stats.module.js create mode 100644 repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js create mode 100644 repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.controller.js delete mode 100644 repo_health/index/static/client/src/components/repo-details/repo-details.html diff --git a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py index 9332c4e..f8869a8 100644 --- a/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py +++ b/repo_health/gh_issues/serializers/GhIssueStatsSerializer.py @@ -62,7 +62,7 @@ def get_avg_lifetime(self, repo): if not isinstance(i.created_at, type(None)): td += (close_event.created_at - i.created_at) avg = (td / closed).days if closed > 0 else closed - return MetricField(True, "Average issue lifetime", 5, 'date', avg) + return MetricField(True, "Average issue lifetime", 5, None, avg) def get_popular_labels(self, repo): # Raw SQL. @@ -82,4 +82,5 @@ def get_avg_maintainer_comments_per_issue(self, repo): issue__in=repo.issues.all(), user__in=repo.maintainers.all() ).count() - return MetricField(True, 'Average maintainer comments per issue', 6, None, comments_from_m / repo.issues.count()) \ No newline at end of file + avg_coms = round(comments_from_m / repo.issues.count(), 5) + return MetricField(True, 'Average maintainer comments per issue', 6, None, avg_coms) \ No newline at end of file diff --git a/repo_health/gh_projects/serializers/StatsUrlSerializer.py b/repo_health/gh_projects/serializers/StatsUrlSerializer.py index 44af90c..58a0762 100644 --- a/repo_health/gh_projects/serializers/StatsUrlSerializer.py +++ b/repo_health/gh_projects/serializers/StatsUrlSerializer.py @@ -16,7 +16,7 @@ class StatsUrlsSerializer(Serializer): repo_details_url = SerializerMethodField() - # issue_stats_url = SerializerMethodField() + issue_stats_url = SerializerMethodField() pr_stats_url = SerializerMethodField() def get_repo_details_url(self, repo): diff --git a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py index 2103cab..7a3776f 100644 --- a/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py +++ b/repo_health/gh_pull_requests/serializers/GhPullRequestStatsSerializer.py @@ -70,7 +70,7 @@ def get_prs_last_year(self, repo): def get_latest_pr_created_at(self, repo): latest = self._most_recent_history.created_at if self._most_recent_history else None - return MetricField(True, 'Latest pull request created at', 3, None, latest) + return MetricField(True, 'Latest pull request created at', 3, 'date', latest) def get_contrib_most_prs(self, repo): contrib = self._contrib_most_prs.login if self._contrib_most_prs else None diff --git a/repo_health/index/static/client/src/components/base-component/base-stats.component.js b/repo_health/index/static/client/src/components/base-component/base-stats.component.js index 174ab4e..40c84a0 100644 --- a/repo_health/index/static/client/src/components/base-component/base-stats.component.js +++ b/repo_health/index/static/client/src/components/base-component/base-stats.component.js @@ -19,10 +19,8 @@ const chartNameEnum = { export default class BaseStatsComponent { - stats = []; - - constructor ( $filter ) { - Object.assign( this, {$filter} ) + constructor ( $http, $filter ) { + Object.assign( this, { $http, $filter} ) } /** * @description Returns the raw data for the metric based on the chart name @@ -37,4 +35,13 @@ export default class BaseStatsComponent { break; } return rawData || 'No'; - }} \ No newline at end of file + } + + getStatsForUrl (url) { + this.$http.get(url).then(stats => { + this.stats = this.$filter('orderBy')(stats.data.metrics, 'ordering'); + this.numOfStatsSections = new Array(Math.floor(this.stats.length / 2)).fill().map((x,i) => {return i}); + this.loadingStats = false; + }); + } +} \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/base-component/base.template.html b/repo_health/index/static/client/src/components/base-component/base.template.html index 8ee0182..ced9361 100644 --- a/repo_health/index/static/client/src/components/base-component/base.template.html +++ b/repo_health/index/static/client/src/components/base-component/base.template.html @@ -23,10 +23,20 @@
{{$ctrl.stats[(2 * i)].display_name}}: {{ $ctrl.getRawDataForChartName(2 * i) }}
-
{{$ctrl.stats[ (2 * i + 1) ].display_name}}: +
+ + {{$ctrl.stats[ (2 * i + 1) ].display_name}}: + {{ $ctrl.getRawDataForChartName((2 * i + 1)) }}
+ +
+ + {{$ctrl.stats[$ctrl.stats.length-1].display_name}}: + + {{ $ctrl.getRawDataForChartName($ctrl.stats.length-1) }} +
diff --git a/repo_health/index/static/client/src/components/components.module.js b/repo_health/index/static/client/src/components/components.module.js index faa6c9e..1641ea1 100644 --- a/repo_health/index/static/client/src/components/components.module.js +++ b/repo_health/index/static/client/src/components/components.module.js @@ -14,12 +14,14 @@ import search from './search/search.module'; import repoDetails from './repo-details/repo-details.module'; import pullReqStats from './pull-req-stats/pull-req-stats.module'; +import issueStats from './issue-stats/issue-stats.module'; const components = angular .module('components', [ search, repoDetails, - pullReqStats + pullReqStats, + issueStats ]) .name; diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js new file mode 100644 index 0000000..8fa1b8d --- /dev/null +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js @@ -0,0 +1,45 @@ +/* +* issue-stats.component.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* Create issue-stats component. +*/ + +import template from '../base-component/base.template'; +import BaseStatsComponent from '../base-component/base-stats.component'; + +const issueStatsComponent = { + template, + bindings: {issueStatsUrl: '='}, + controller: class issueStatsComponent extends BaseStatsComponent { + stats = null; + loadingStats = true; + loadingMsg = "Loading issue stats..."; + numOfStatsSections = 0; + + + constructor( $http, $filter ) { + super($http, $filter); + 'ngInject'; + Object.assign(this, { $http }); + } + + $onInit() { + if (this.issueStatsUrl) { + this.getStatsForUrl(this.issueStatsUrl); + // this.$http.get(this.issueStatsUrl).then(stats => { + // this.stats = this.$filter('orderBy')(stats.data.metrics, 'ordering'); + // this.numOfStatsSections = new Array(Math.floor(this.stats.length / 2)).fill().map((x,i) => {return i}); + // this.loadingStats = false; + // }); + } + } + } +}; + +export default issueStatsComponent; diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.controller.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.controller.js new file mode 100644 index 0000000..ddc01e5 --- /dev/null +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.controller.js @@ -0,0 +1,22 @@ +/* +*issue-stats.controller.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* Controller for the issue stats named view. +* +*/ + +import BaseStatsController from '../base-component/base-stats.controller'; + +export default class IssueStatsController extends BaseStatsController { + + constructor ($state, issueStatsUrl) { + super($state, issueStatsUrl); + Object.assign(this, {$state, issueStatsUrl}); + } +} \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.module.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.module.js new file mode 100644 index 0000000..bd04f5c --- /dev/null +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.module.js @@ -0,0 +1,20 @@ +/* +* issue-stats..module.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* Definition for the issue stats module +*/ + +import issueStatsComponent from './issue-stats.component'; + +const components = angular + .module('components.issue-stats', []) + .component('issueStats', issueStatsComponent) + .name; + +export default components; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js new file mode 100644 index 0000000..fda04e6 --- /dev/null +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js @@ -0,0 +1,59 @@ +/* +* issue-stats..spec.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* This is the test file for the issue stats component +*/ + +const module = angular.mock.module; + +describe('Issue Stats', () => { + + beforeEach(module( + 'app.resources', + 'components.search', + 'components.repo-details', + 'components.pull-req-stats', + 'components.issue-stats' + )); + + describe('IssueStatsComponent', () => { + let $componentController, $httpBackend, $apiUrl; + let controller, getIssueStatsUrl; + + beforeEach(inject(($injector) => { + $componentController = $injector.get('$componentController'); + $httpBackend = $injector.get('$httpBackend'); + $apiUrl = $injector.get('$apiUrl'); + getIssueStatsUrl = `${$apiUrl}/${jasmine.any(Number)}/issues`; + controller = $componentController('issueStats', null, {issueStatsUrl: getIssueStatsUrl}); + $httpBackend.when('GET', getIssueStatsUrl).respond(200, {metrics: [{ + ordering: 1 + }]}); + + })); + + afterEach(() => { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + describe('constructor', () => { + + it('should setup the controller', () => { + expect(controller).toBeDefined(); + }); + + it('should make a request to get the stats in the $onInit method', () => { + $httpBackend.expectGET(getIssueStatsUrl) + controller.$onInit(); + $httpBackend.flush(); + }) + }); + }); +}); \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index 4ae27a6..72a5318 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -60,18 +60,14 @@ const pullReqStatsComponent = { }; constructor( $http, $filter ) { - super($filter); + super($http, $filter); 'ngInject'; Object.assign(this, { $http }); } $onInit() { if (this.prStatsUrl) { - this.$http.get(this.prStatsUrl).then(stats => { - this.stats = this.$filter('orderBy')(stats.data.metrics, 'ordering'); - this.numOfStatsSections = new Array(Math.floor(this.stats.length / 2)).fill().map((x,i) => {return i}); - this.loadingStats = false; - }); + this.getStatsForUrl(this.prStatsUrl); } } } diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.controller.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.controller.js new file mode 100644 index 0000000..a30bd7a --- /dev/null +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.controller.js @@ -0,0 +1,22 @@ +/* +*pull-req-stats.controller.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* Controller for the pr stats named view. +* +*/ + +import BaseStatsController from '../base-component/base-stats.controller'; + +export default class PrStatsController extends BaseStatsController { + + constructor ($state, prStatsUrl) { + super($state, prStatsUrl); + Object.assign(this, {$state, prStatsUrl}); + } +} diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js index af3c22c..4219dcd 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js @@ -7,7 +7,7 @@ * Author(s) of this file: * J.Harding * -* This is the test file for the search component +* This is the test file for the pull request component */ const module = angular.mock.module; @@ -18,7 +18,8 @@ describe('Pull Req Stats', () => { 'app.resources', 'components.search', 'components.repo-details', - 'components.pull-req-stats' + 'components.pull-req-stats', + 'components.issue-stats' )); describe('PullReqStatsController', () => { @@ -31,7 +32,11 @@ describe('Pull Req Stats', () => { $apiUrl = $injector.get('$apiUrl'); getPrStatsUrl = `${$apiUrl}/${jasmine.any(Number)}/pull-requests`; controller = $componentController('pullReqStats', null, {prStatsUrl: getPrStatsUrl}); - $httpBackend.when('GET', getPrStatsUrl).respond(200, {some: 'cakephp', data: 15}); + $httpBackend.when('GET', getPrStatsUrl).respond(200, {metrics: [ + { + ordering: 0 + } + ]}); })); diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index e465186..0e494ac 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -24,18 +24,14 @@ const repoDetailsComponent = { numOfStatsSections = 0; constructor($http, $filter) { - super( $filter ); + super($http, $filter ); 'ngInject'; Object.assign(this, { $http }); } $onInit() { if (this.detailsUrl) { - this.$http.get(this.detailsUrl).then(details => { - this.stats = this.$filter('orderBy')(details.data.metrics, 'ordering'); - this.numOfStatsSections = new Array(this.stats.length / 2).fill().map((x,i) => {return i}); - this.loadingStats = false; - }); + this.getStatsForUrl(this.detailsUrl); } } } diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.html b/repo_health/index/static/client/src/components/repo-details/repo-details.html deleted file mode 100644 index 75a4cdf..0000000 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.html +++ /dev/null @@ -1,35 +0,0 @@ - - - -
- Loading your repository... Please wait... -
- -
-
-
- - - {{::$ctrl.details.name}} - {{::$ctrl.details.description}} - - - -
-
Language: {{$ctrl.details.language}}
-
Contributions: {{$ctrl.details.contribs_count}}
-
- -
-
Watchers: {{$ctrl.details.watchers_count}}
-
Commits: {{$ctrl.details.commits_count}}
-
- -
-
Milestones: {{$ctrl.details.milestones_count}}
-
Forks: {{$ctrl.details.forks_count}}
-
-
-
-
-
diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index 0af2e96..63fd73e 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -20,6 +20,8 @@ describe('Repo Details', () => { 'app.resources', 'components.search', 'components.repo-details', + 'components.pull-req-stats', + 'components.issue-stats' )); beforeEach(inject(($injector) => { $httpBackend = $injector.get("$httpBackend"); diff --git a/repo_health/index/static/client/src/main.component.js b/repo_health/index/static/client/src/main.component.js index d722836..c5f3d71 100644 --- a/repo_health/index/static/client/src/main.component.js +++ b/repo_health/index/static/client/src/main.component.js @@ -18,6 +18,7 @@ const template = `
+
`; diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index c8e0b76..fa24279 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -19,6 +19,8 @@ import resources from './resources'; import components from 'components/components.module.js'; import mainComponent from './main.component'; import RepoDetailsController from 'components/repo-details/repo-details.controller'; +import IssueStatsController from 'components/issue-stats/issue-stats.controller'; +import PrStatsController from 'components/pull-req-stats/pull-req-stats.controller'; //Styles import 'global.css'; @@ -53,15 +55,19 @@ export const main = angular.module('repo-health', [ template: '', }, 'pull-req-stats': { - controller: class PrStatUrl { - constructor(prStatsUrl) { - this.prStatsUrl = prStatsUrl; - } - }, + controller: PrStatsController, controllerAs: '$ctrl', resolve: { prStatsUrl: (statsUrls) => { return statsUrls['pr_stats_url']; } }, template: '' + }, + 'issue-stats': { + controller: IssueStatsController, + controllerAs: '$ctrl', + template: '', + resolve: { + issueStatsUrl: (statsUrls) => { return statsUrls['issue_stats_url']; } + } } } }) diff --git a/repo_health/index/static/karma.conf.js b/repo_health/index/static/karma.conf.js index 3735899..a7f9053 100644 --- a/repo_health/index/static/karma.conf.js +++ b/repo_health/index/static/karma.conf.js @@ -27,7 +27,7 @@ module.exports = (config) => { ], plugins: [ require('karma-jasmine'), - require('karma-phantomjs-launcher'), + require('karma-chrome-launcher'), require('karma-webpack') ], preprocessors: { @@ -38,7 +38,7 @@ module.exports = (config) => { colors: true, logLevel: config.LOG_INFO, autoWatch: true, - browsers: ['PhantomJS'], + browsers: ['Chrome'], singleRun: false, concurrency: Infinity, }); diff --git a/repo_health/index/static/package.json b/repo_health/index/static/package.json index ee0f604..60c938a 100644 --- a/repo_health/index/static/package.json +++ b/repo_health/index/static/package.json @@ -32,6 +32,7 @@ "html-webpack-plugin": "^2.28.0", "jasmine-core": "^2.5.2", "karma": "^1.5.0", + "karma-chrome-launcher": "^2.0.0", "karma-jasmine": "^1.1.0", "karma-phantomjs-launcher": "^1.0.4", "karma-webpack": "^2.0.2", From 2f9ec49d5d824d0108d3e1a2452ea21b21caa3da Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Sat, 25 Mar 2017 16:39:04 -0500 Subject: [PATCH 79/99] Initial Docker implementation --- docker/Dockerfile | 24 ++++++++++++++++++++++++ docker/docker-compose.yml | 13 +++++++++++++ docker/init_db.sh | 5 +++++ 3 files changed, 42 insertions(+) create mode 100644 docker/Dockerfile create mode 100644 docker/docker-compose.yml create mode 100644 docker/init_db.sh diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..31bbe76 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,24 @@ + FROM python:3.6 + ENV PYTHONUNBUFFERED 1 + ENTRYPOINT ["repo-health"] + LABEL Description="This image supplies the server needed for repo-health." + + # Setting up database + RUN apt-get update && apt-get install -y \ + curl + RUN curl -O https://ghtstorage.blob.core.windows.net/downloads/msr14-mysql.gz + RUN gzip -d msr14-mysql.gz + COPY init_db.sh /www/ + RUN chmod +x /www/init_db.sh && /www/init_db.sh + + RUN mkdir /www + WORKDIR /www + COPY ../requirements.txt /www/ + RUN pip install -r requirements.txt + COPY ../. /www/ + + WORKDIR repo_health/index/static + RUN npm install && npm run dist + RUN python manage.py migrate + + EXPOSE 8080 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..f312e9c --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,13 @@ + version: '2' + services: + db: + image: mysql + web: + build: . + command: python manage.py runserver + volumes: + - .:/www + ports: + - "8080:8080" + depends_on: + - db diff --git a/docker/init_db.sh b/docker/init_db.sh new file mode 100644 index 0000000..5a3b8a2 --- /dev/null +++ b/docker/init_db.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# /usr/bin/mysqld_safe & +# sleep 5 +# mysql -u root -e "CREATE DATABASE msr14" +# mysql -u root msr14 < /www/msr14-mysql.sql From 6c35021b6b3ade1acb2d6e29b2a744aab5cbf021 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 27 Mar 2017 14:41:21 -0500 Subject: [PATCH 80/99] Remove example code for chart js. --- docs/README.md | 4 +- .../pull-req-stats.component.js | 37 ------------------- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/docs/README.md b/docs/README.md index 99edcca..71a191f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ -#REST API README +# REST API README -##Purpose +## Purpose GitHub maintains a REST API so why do we need another? - The reason to host and supply the data independentluy of GitHub enables us to structure the data in a fashion suitable for our purpose. diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index 72a5318..f5bd3c1 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -21,43 +21,6 @@ const pullReqStatsComponent = { loadingStats = true; loadingMsg = "Loading pull request stats..."; numOfStatsSections = 0; - - labels = ['Jan', 'feb', 'Mar', 'April', 'May', 'Jun', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; - series = ['Series A', 'Series B']; - data = [ - [65, 59, 80, 81, 56, 55, 40], - [28, 48, 40, 19, 86, 27, 90] - ]; - onClick = function (points, evt) { - console.log(points, evt); - }; - onHover = function (points) { - if (points.length > 0) { - console.log('Point', points[0].value); - } else { - console.log('No point'); - } - }; - datasetOverride = [{ yAxisID: 'y-axis-1' }, { yAxisID: 'y-axis-2' }]; - - options = { - scales: { - yAxes: [ - { - id: 'y-axis-1', - type: 'linear', - display: true, - position: 'left' - }, - { - id: 'y-axis-2', - type: 'linear', - display: true, - position: 'right' - } - ] - } - }; constructor( $http, $filter ) { super($http, $filter); From 7b2e4d6c569b1519d22083f7a4bcc2c2b0119a78 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 27 Mar 2017 19:40:26 -0500 Subject: [PATCH 81/99] Removed controllers. --- .../base-component/base-stats.controller.js | 21 ----------------- .../issue-stats/issue-stats.component.js | 19 ++++++++------- .../issue-stats/issue-stats.controller.js | 22 ------------------ .../pull-req-stats.controller.js | 22 ------------------ .../repo-details/repo-details.controller.js | 23 ------------------- .../src/components/search/search.module.js | 4 +++- .../index/static/client/src/main.module.js | 14 ++++------- 7 files changed, 16 insertions(+), 109 deletions(-) delete mode 100644 repo_health/index/static/client/src/components/base-component/base-stats.controller.js delete mode 100644 repo_health/index/static/client/src/components/issue-stats/issue-stats.controller.js delete mode 100644 repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.controller.js delete mode 100644 repo_health/index/static/client/src/components/repo-details/repo-details.controller.js diff --git a/repo_health/index/static/client/src/components/base-component/base-stats.controller.js b/repo_health/index/static/client/src/components/base-component/base-stats.controller.js deleted file mode 100644 index 5305bc9..0000000 --- a/repo_health/index/static/client/src/components/base-component/base-stats.controller.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -* base-stats.controller.js - (C) Copyright - 2017 -* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. -* -* SPDX-License-Identifier: MIT -* -* Author(s) of this file: -* J.Harding -* -* Base stats controller to handle an error state if no repos are returned for an owner login and name request -*/ - - -export default class BaseStatsController { - - constructor ($state, Urls) { - if (!Urls) { - $state.go('search', {error:true}); - } - } -} diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js index 8fa1b8d..2c276ee 100644 --- a/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js @@ -16,27 +16,26 @@ import BaseStatsComponent from '../base-component/base-stats.component'; const issueStatsComponent = { template, bindings: {issueStatsUrl: '='}, - controller: class issueStatsComponent extends BaseStatsComponent { + controller: class issueStatsComponent { stats = null; loadingStats = true; loadingMsg = "Loading issue stats..."; numOfStatsSections = 0; - constructor( $http, $filter ) { - super($http, $filter); + constructor( $http, $state ) { 'ngInject'; - Object.assign(this, { $http }); + Object.assign(this, { $http, $state }); } $onInit() { if (this.issueStatsUrl) { - this.getStatsForUrl(this.issueStatsUrl); - // this.$http.get(this.issueStatsUrl).then(stats => { - // this.stats = this.$filter('orderBy')(stats.data.metrics, 'ordering'); - // this.numOfStatsSections = new Array(Math.floor(this.stats.length / 2)).fill().map((x,i) => {return i}); - // this.loadingStats = false; - // }); + // TODO Write service to make API request for stats. + // this.getStatsForUrl(this.issueStatsUrl); + } else { + this.$state.go('search', { + error: true + }); } } } diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.controller.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.controller.js deleted file mode 100644 index ddc01e5..0000000 --- a/repo_health/index/static/client/src/components/issue-stats/issue-stats.controller.js +++ /dev/null @@ -1,22 +0,0 @@ -/* -*issue-stats.controller.js - (C) Copyright - 2017 -* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. -* -* SPDX-License-Identifier: MIT -* -* Author(s) of this file: -* J.Harding -* -* Controller for the issue stats named view. -* -*/ - -import BaseStatsController from '../base-component/base-stats.controller'; - -export default class IssueStatsController extends BaseStatsController { - - constructor ($state, issueStatsUrl) { - super($state, issueStatsUrl); - Object.assign(this, {$state, issueStatsUrl}); - } -} \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.controller.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.controller.js deleted file mode 100644 index a30bd7a..0000000 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.controller.js +++ /dev/null @@ -1,22 +0,0 @@ -/* -*pull-req-stats.controller.js - (C) Copyright - 2017 -* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. -* -* SPDX-License-Identifier: MIT -* -* Author(s) of this file: -* J.Harding -* -* Controller for the pr stats named view. -* -*/ - -import BaseStatsController from '../base-component/base-stats.controller'; - -export default class PrStatsController extends BaseStatsController { - - constructor ($state, prStatsUrl) { - super($state, prStatsUrl); - Object.assign(this, {$state, prStatsUrl}); - } -} diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.controller.js b/repo_health/index/static/client/src/components/repo-details/repo-details.controller.js deleted file mode 100644 index 7692834..0000000 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.controller.js +++ /dev/null @@ -1,23 +0,0 @@ -/* -*repo-details.controller.js - (C) Copyright - 2017 -* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. -* -* SPDX-License-Identifier: MIT -* -* Author(s) of this file: -* J.Harding -* -* Extend base stats controller to handle error state. -* Adds the ability to inject the specific resolve of the details url. -* -*/ - -import BaseStatsController from '../base-component/base-stats.controller'; - -export default class RepoDetailsController extends BaseStatsController { - - constructor ($state, detailsUrl) { - super($state, detailsUrl); - Object.assign(this, {$state, detailsUrl}); - } -} \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/search/search.module.js b/repo_health/index/static/client/src/components/search/search.module.js index 75e7b2a..1021c05 100644 --- a/repo_health/index/static/client/src/components/search/search.module.js +++ b/repo_health/index/static/client/src/components/search/search.module.js @@ -22,7 +22,9 @@ const components = angular $stateProvider.state('search', { url: '/search', template: '', - params: { error: false } + params: { + error: false + } }) }) .name; diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index fa24279..cba31f3 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -18,9 +18,6 @@ import 'angular-chart.js'; import resources from './resources'; import components from 'components/components.module.js'; import mainComponent from './main.component'; -import RepoDetailsController from 'components/repo-details/repo-details.controller'; -import IssueStatsController from 'components/issue-stats/issue-stats.controller'; -import PrStatsController from 'components/pull-req-stats/pull-req-stats.controller'; //Styles import 'global.css'; @@ -47,24 +44,21 @@ export const main = angular.module('repo-health', [ }, views: { 'repo-details': { - controller: RepoDetailsController, resolve: { - detailsUrl: (statsUrls) => { return statsUrls["repo_details_url"]; } + detailsUrl: (statsUrls) => { return statsUrls['repo_details_url']; } }, controllerAs: '$ctrl', - template: '', + template: '', }, 'pull-req-stats': { - controller: PrStatsController, controllerAs: '$ctrl', resolve: { prStatsUrl: (statsUrls) => { return statsUrls['pr_stats_url']; } }, - template: '' + template: '' }, 'issue-stats': { - controller: IssueStatsController, controllerAs: '$ctrl', - template: '', + template: '', resolve: { issueStatsUrl: (statsUrls) => { return statsUrls['issue_stats_url']; } } From 524977bec75c6d82a763a9c7c5611c5465147fef Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 27 Mar 2017 21:28:59 -0500 Subject: [PATCH 82/99] Moved base component to a service. Tests pass but metrics are not showing in the UI. --- .../base-component/base-stats.component.js | 47 --------------- .../issue-stats/issue-stats.component.js | 19 ++++--- .../issue-stats/issue-stats.spec.js | 18 +++--- .../pull-req-stats.component.js | 24 +++++--- .../pull-req-stats/pull-req-stats.module.js | 3 +- .../pull-req-stats/pull-req-stats.spec.js | 30 +++++----- .../repo-details/repo-details.component.js | 25 +++++--- .../repo-details/repo-details.spec.js | 20 +++++-- .../src/components/search/search.module.js | 2 +- .../base.template.html | 0 .../src/components/utils/stats.service.js | 57 +++++++++++++++++++ .../components/utils/stats.service.spec.js | 44 ++++++++++++++ .../index/static/client/src/main.module.js | 2 + 13 files changed, 191 insertions(+), 100 deletions(-) delete mode 100644 repo_health/index/static/client/src/components/base-component/base-stats.component.js rename repo_health/index/static/client/src/components/{base-component => utils}/base.template.html (100%) create mode 100644 repo_health/index/static/client/src/components/utils/stats.service.js create mode 100644 repo_health/index/static/client/src/components/utils/stats.service.spec.js diff --git a/repo_health/index/static/client/src/components/base-component/base-stats.component.js b/repo_health/index/static/client/src/components/base-component/base-stats.component.js deleted file mode 100644 index 40c84a0..0000000 --- a/repo_health/index/static/client/src/components/base-component/base-stats.component.js +++ /dev/null @@ -1,47 +0,0 @@ -/* -* base-stats.component.js - (C) Copyright - 2017 -* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. -* -* SPDX-License-Identifier: MIT -* -* Author(s) of this file: -* J.Harding -* -* This is the base controller for the components to hold some commone methods. -*/ - -/** - * Tracks constants for chart names. - */ -const chartNameEnum = { - dateChart: 'date' // Track date as a chart to tell what metrics are dates -} - -export default class BaseStatsComponent { - - constructor ( $http, $filter ) { - Object.assign( this, { $http, $filter} ) - } - /** - * @description Returns the raw data for the metric based on the chart name - * @param ind - * @returns {*|string} - */ - getRawDataForChartName(ind) { - let rawData = this.stats[ind].raw_data; - switch ( this.stats[ind].chart_name ) { - case chartNameEnum.dateChart: - rawData = this.$filter('date')(rawData); - break; - } - return rawData || 'No'; - } - - getStatsForUrl (url) { - this.$http.get(url).then(stats => { - this.stats = this.$filter('orderBy')(stats.data.metrics, 'ordering'); - this.numOfStatsSections = new Array(Math.floor(this.stats.length / 2)).fill().map((x,i) => {return i}); - this.loadingStats = false; - }); - } -} \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js index 2c276ee..db48a13 100644 --- a/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js @@ -10,28 +10,31 @@ * Create issue-stats component. */ -import template from '../base-component/base.template'; -import BaseStatsComponent from '../base-component/base-stats.component'; +import template from '../utils/base.template'; const issueStatsComponent = { template, - bindings: {issueStatsUrl: '='}, + bindings: { + issueStatsUrl: '=' + }, controller: class issueStatsComponent { stats = null; loadingStats = true; loadingMsg = "Loading issue stats..."; numOfStatsSections = 0; - - constructor( $http, $state ) { + constructor( $http, $state, StatsService ) { 'ngInject'; - Object.assign(this, { $http, $state }); + Object.assign(this, { $http, $state, StatsService }); } $onInit() { if (this.issueStatsUrl) { - // TODO Write service to make API request for stats. - // this.getStatsForUrl(this.issueStatsUrl); + this.StatsService.getStatsForUrl(this.issueStatsUrl).then(stats => { + this.stats = stats; + this.loadingStats = false; + this.numOfStatsSections = this.StatsService.getRangeForSections(this.stats.length); + }); } else { this.$state.go('search', { error: true diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js index fda04e6..852b2a4 100644 --- a/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js @@ -1,5 +1,5 @@ /* -* issue-stats..spec.js - (C) Copyright - 2017 +* issue-stats.spec.js - (C) Copyright - 2017 * This software is copyrighted to contributors listed in CONTRIBUTIONS.md. * * SPDX-License-Identifier: MIT @@ -15,12 +15,17 @@ const module = angular.mock.module; describe('Issue Stats', () => { beforeEach(module( - 'app.resources', - 'components.search', - 'components.repo-details', - 'components.pull-req-stats', + 'repo-health', 'components.issue-stats' - )); + ), ($provide) => { + $provide.provider('StatsService', () => { + return { + then: () => { + return "Mock"; + } + }; + }) + }); describe('IssueStatsComponent', () => { let $componentController, $httpBackend, $apiUrl; @@ -35,7 +40,6 @@ describe('Issue Stats', () => { $httpBackend.when('GET', getIssueStatsUrl).respond(200, {metrics: [{ ordering: 1 }]}); - })); afterEach(() => { diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js index f5bd3c1..1c4f2e2 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.component.js @@ -10,27 +10,35 @@ * This is the creation of the pull-req-stats component. */ -import template from '../base-component/base.template'; -import BaseStatsComponent from '../base-component/base-stats.component'; +import template from '../utils/base.template'; const pullReqStatsComponent = { template, - bindings: {prStatsUrl: '='}, - controller: class pullReqStatsComponent extends BaseStatsComponent { + bindings: { + prStatsUrl: '=' + }, + controller: class pullReqStatsComponent { stats = null; loadingStats = true; loadingMsg = "Loading pull request stats..."; numOfStatsSections = 0; - constructor( $http, $filter ) { - super($http, $filter); + constructor( $http, $state, StatsService ) { 'ngInject'; - Object.assign(this, { $http }); + Object.assign(this, { $http, $state, StatsService }); } $onInit() { if (this.prStatsUrl) { - this.getStatsForUrl(this.prStatsUrl); + this.StatsService.getStatsForUrl(this.prStatsUrl).then(stats => { + this.stats = stats; + this.loadingStats = false; + this.numOfStatsSections = this.StatsService.getRangeForSections(this.stats.length); + }); + } else { + this.$state.go('search', { + error: true + }); } } } diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js index f6e6d4f..aa3eccd 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.module.js @@ -10,12 +10,11 @@ * This is the module definition for the pr stats module */ -import uiRouter from 'angular-ui-router'; import pullReqStatsComponent from './pull-req-stats.component'; const components = angular .module('components.pull-req-stats', []) - .component('pullReqStats', pullReqStatsComponent) + .component('pullReqStats', pullReqStatsComponent) .name; export default components; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js index 4219dcd..009ee08 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js @@ -15,12 +15,17 @@ const module = angular.mock.module; describe('Pull Req Stats', () => { beforeEach(module( - 'app.resources', - 'components.search', - 'components.repo-details', - 'components.pull-req-stats', - 'components.issue-stats' - )); + 'repo-health', + 'components.pull-req-stats' + ), ($provide) => { + $provide.provider('StatsService', () => { + return { + then: () => { + return "Mock"; + } + }; + }) + }); describe('PullReqStatsController', () => { let $componentController, $httpBackend, $apiUrl; @@ -31,13 +36,12 @@ describe('Pull Req Stats', () => { $httpBackend = $injector.get('$httpBackend'); $apiUrl = $injector.get('$apiUrl'); getPrStatsUrl = `${$apiUrl}/${jasmine.any(Number)}/pull-requests`; - controller = $componentController('pullReqStats', null, {prStatsUrl: getPrStatsUrl}); - $httpBackend.when('GET', getPrStatsUrl).respond(200, {metrics: [ - { - ordering: 0 - } - ]}); - + controller = $componentController('pullReqStats', null, { + prStatsUrl: getPrStatsUrl + }); + $httpBackend.when('GET', getPrStatsUrl).respond(200, {metrics: [{ + ordering: 0 + }]}); })); afterEach(() => { diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index 0e494ac..7123942 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -10,28 +10,37 @@ * This is the creation of the search component. */ -import template from '../base-component/base.template'; -import BaseStatsComponent from '../base-component/base-stats.component'; +import template from '../utils/base.template'; const repoDetailsComponent = { template, - bindings: {detailsUrl: '='}, - controller: class repoDetailsComponent extends BaseStatsComponent { + bindings: { + detailsUrl: '=' + }, + controller: class repoDetailsComponent { loadingStats = true; loadingMsg = "Loading general repo stats..."; stats = null; numOfStatsSections = 0; - constructor($http, $filter) { - super($http, $filter ); + constructor($http, StatsService) { 'ngInject'; - Object.assign(this, { $http }); + Object.assign(this, { $http, StatsService }); } $onInit() { if (this.detailsUrl) { - this.getStatsForUrl(this.detailsUrl); + // this.getStatsForUrl(this.detailsUrl); + this.StatsService.getStatsForUrl(this.detailsUrl).then(stats => { + this.stats = stats; + this.loadingStats = false; + this.numOfStatsSections = this.StatsService.getRangeForSections(this.stats.length); + }); + } else { + this.$state.go('search', { + error: true + }); } } } diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index 63fd73e..6083b1e 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -17,12 +17,17 @@ describe('Repo Details', () => { let $apiUrl, getStatsReqUrl, getDetailsUrl; beforeEach(module( - 'app.resources', - 'components.search', + 'repo-health', 'components.repo-details', - 'components.pull-req-stats', - 'components.issue-stats' - )); + ), ($provide) => { + $provide.provider('StatsService', () => { + return { + then: () => { + return "Mock"; + } + }; + }) + }); beforeEach(inject(($injector) => { $httpBackend = $injector.get("$httpBackend"); $apiUrl = $injector.get('$apiUrl'); @@ -42,7 +47,10 @@ describe('Repo Details', () => { beforeEach(inject(($injector) => { $componentController = $injector.get('$componentController'); - controller = $componentController('repoDetails', null, { detailsUrl: getDetailsUrl, stats: []}); + controller = $componentController('repoDetails', null, { + detailsUrl: getDetailsUrl, + stats: [] + }); $httpBackend.when('GET', getDetailsUrl).respond(200, { metrics: [{ ordering: 1 diff --git a/repo_health/index/static/client/src/components/search/search.module.js b/repo_health/index/static/client/src/components/search/search.module.js index 1021c05..e6b5341 100644 --- a/repo_health/index/static/client/src/components/search/search.module.js +++ b/repo_health/index/static/client/src/components/search/search.module.js @@ -23,7 +23,7 @@ const components = angular url: '/search', template: '', params: { - error: false + error: false } }) }) diff --git a/repo_health/index/static/client/src/components/base-component/base.template.html b/repo_health/index/static/client/src/components/utils/base.template.html similarity index 100% rename from repo_health/index/static/client/src/components/base-component/base.template.html rename to repo_health/index/static/client/src/components/utils/base.template.html diff --git a/repo_health/index/static/client/src/components/utils/stats.service.js b/repo_health/index/static/client/src/components/utils/stats.service.js new file mode 100644 index 0000000..2545dfe --- /dev/null +++ b/repo_health/index/static/client/src/components/utils/stats.service.js @@ -0,0 +1,57 @@ +/* +* stats.service.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* This is the base controller for the components to hold some commone methods. +*/ + +/** + * Tracks constants for chart names. + */ +const chartNameEnum = { + dateChart: 'date' // Track date as a chart to tell what metrics are dates +} + +class StatsService { + + constructor ( $http, $filter ) { + Object.assign( this, { $http, $filter} ) + } + + getRangeForSections(statsLength) { + return [...Array(Math.floor(statsLength / 2)).keys()]; + } + + /** + * @description Returns the raw data for the metric based on the chart name + * @param index + * @returns {*|string} + */ + getRawDataForChartName(index) { + let rawData = this.stats[index].raw_data; + switch ( this.stats[index].chart_name ) { + case chartNameEnum.dateChart: + rawData = this.$filter('date')(rawData); + break; + } + return rawData || 'No'; + } + + /** + * @description Makes a get request to the given url. + * @param url + */ + getStatsForUrl (url) { + return this.$http.get(url).then(stats => { + stats = this.$filter('orderBy')(stats.data.metrics, 'ordering'); + return stats; + }); + } +} + +export default StatsService; \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/utils/stats.service.spec.js b/repo_health/index/static/client/src/components/utils/stats.service.spec.js new file mode 100644 index 0000000..9a60297 --- /dev/null +++ b/repo_health/index/static/client/src/components/utils/stats.service.spec.js @@ -0,0 +1,44 @@ +/* +* issue-stats.spec.js - (C) Copyright - 2017 +* This software is copyrighted to contributors listed in CONTRIBUTIONS.md. +* +* SPDX-License-Identifier: MIT +* +* Author(s) of this file: +* J.Harding +* +* This is the test file for the issue stats component +*/ + +const module = angular.mock.module; + +describe("StatsService", () => { + let StatsService, $httpBackend; + let someFakeUrl = 'some/fake/url'; + beforeEach(module( + 'repo-health' + )); + + beforeEach(inject(($injector) => { + StatsService = $injector.get('StatsService'); + $httpBackend = $injector.get('$httpBackend'); + })); + + afterEach(() => { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + describe('getStatsForUrl', () => { + beforeEach(() => { + $httpBackend.when('GET', someFakeUrl).respond(200, { + metrics: [] + }); + }); + it('should make a request to the given url', () => { + $httpBackend.expectGET(someFakeUrl); + StatsService.getStatsForUrl(someFakeUrl); + $httpBackend.flush(); + }) + }) +}) \ No newline at end of file diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index cba31f3..98ac1d2 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -18,6 +18,7 @@ import 'angular-chart.js'; import resources from './resources'; import components from 'components/components.module.js'; import mainComponent from './main.component'; +import StatsService from 'components/utils/stats.service'; //Styles import 'global.css'; @@ -30,6 +31,7 @@ export const main = angular.module('repo-health', [ 'chart.js' ]) .component('main', mainComponent) + .service('StatsService', StatsService) .config(($locationProvider, $urlRouterProvider, $mdThemingProvider, $stateProvider) => { 'ngInject'; $locationProvider.hashPrefix(''); From de0b9efecc8d554ef7438b394312a04b37e7ee1a Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 27 Mar 2017 21:42:29 -0500 Subject: [PATCH 83/99] Metrics are displayed. --- .../client/src/components/utils/base.template.html | 6 +++--- .../client/src/components/utils/stats.service.js | 11 ++++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/repo_health/index/static/client/src/components/utils/base.template.html b/repo_health/index/static/client/src/components/utils/base.template.html index ced9361..ff8998e 100644 --- a/repo_health/index/static/client/src/components/utils/base.template.html +++ b/repo_health/index/static/client/src/components/utils/base.template.html @@ -21,13 +21,13 @@
{{$ctrl.stats[(2 * i)].display_name}}: - {{ $ctrl.getRawDataForChartName(2 * i) }} + {{ $ctrl.StatsService.getRawDataForChartName($ctrl.stats[(2 * i)]) }}
{{$ctrl.stats[ (2 * i + 1) ].display_name}}: - {{ $ctrl.getRawDataForChartName((2 * i + 1)) }} + {{ $ctrl.StatsService.getRawDataForChartName($ctrl.stats[ (2 * i + 1) ]) }}
@@ -35,7 +35,7 @@ {{$ctrl.stats[$ctrl.stats.length-1].display_name}}: - {{ $ctrl.getRawDataForChartName($ctrl.stats.length-1) }} + {{ $ctrl.StatsService.getRawDataForChartName($ctrl.stats.length-1) }}
diff --git a/repo_health/index/static/client/src/components/utils/stats.service.js b/repo_health/index/static/client/src/components/utils/stats.service.js index 2545dfe..cb92bb1 100644 --- a/repo_health/index/static/client/src/components/utils/stats.service.js +++ b/repo_health/index/static/client/src/components/utils/stats.service.js @@ -23,6 +23,11 @@ class StatsService { Object.assign( this, { $http, $filter} ) } + /** + * @description Returns an array of indices to enable interation over a range in a template + * @param statsLength + * @returns {[*]} + */ getRangeForSections(statsLength) { return [...Array(Math.floor(statsLength / 2)).keys()]; } @@ -32,9 +37,9 @@ class StatsService { * @param index * @returns {*|string} */ - getRawDataForChartName(index) { - let rawData = this.stats[index].raw_data; - switch ( this.stats[index].chart_name ) { + getRawDataForChartName(stat) { + let rawData = stat.raw_data; + switch ( stat.chart_name ) { case chartNameEnum.dateChart: rawData = this.$filter('date')(rawData); break; From 76273ce9f41b77a24ca6065cb548f045ac5a1a2e Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 27 Mar 2017 22:11:14 -0500 Subject: [PATCH 84/99] Some tests for the stats service. --- .../src/components/utils/stats.service.js | 4 +- .../components/utils/stats.service.spec.js | 47 ++++++++++++++++--- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/repo_health/index/static/client/src/components/utils/stats.service.js b/repo_health/index/static/client/src/components/utils/stats.service.js index cb92bb1..bd70242 100644 --- a/repo_health/index/static/client/src/components/utils/stats.service.js +++ b/repo_health/index/static/client/src/components/utils/stats.service.js @@ -24,7 +24,7 @@ class StatsService { } /** - * @description Returns an array of indices to enable interation over a range in a template + * @description Returns an array of indices to enable iteration over a range in a template * @param statsLength * @returns {[*]} */ @@ -34,7 +34,7 @@ class StatsService { /** * @description Returns the raw data for the metric based on the chart name - * @param index + * @param stat * @returns {*|string} */ getRawDataForChartName(stat) { diff --git a/repo_health/index/static/client/src/components/utils/stats.service.spec.js b/repo_health/index/static/client/src/components/utils/stats.service.spec.js index 9a60297..e7d2106 100644 --- a/repo_health/index/static/client/src/components/utils/stats.service.spec.js +++ b/repo_health/index/static/client/src/components/utils/stats.service.spec.js @@ -24,21 +24,56 @@ describe("StatsService", () => { $httpBackend = $injector.get('$httpBackend'); })); - afterEach(() => { - $httpBackend.verifyNoOutstandingExpectation(); - $httpBackend.verifyNoOutstandingRequest(); - }); - describe('getStatsForUrl', () => { beforeEach(() => { $httpBackend.when('GET', someFakeUrl).respond(200, { metrics: [] }); }); + afterEach(() => { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + it('should make a request to the given url', () => { $httpBackend.expectGET(someFakeUrl); StatsService.getStatsForUrl(someFakeUrl); $httpBackend.flush(); + }); + }) + + describe('getStatsSections', () => { + it('should return an array the floor of half the size input', () => { + let range = StatsService.getRangeForSections(9); + expect(Array.isArray(range)).toBeTruthy(); + expect(range.length).toBe(4); + }); + }); + + describe('getRawDataForChartName', () => { + it('should call the $filter if chart name is `date`', () => { + spyOn(StatsService, '$filter').and.callThrough(); + let mockStat = { + chart_name: 'date', + raw_data: "2013-10-05T11:40:36"// Must have a valid date format for $filter to use it + } + expect(StatsService.getRawDataForChartName(mockStat)).not.toBe(mockStat.raw_data); + expect(StatsService.$filter).toHaveBeenCalledWith('date'); + }); + + it('should the raw data is the chart name is null', () => { + let mockStat = { + raw_data: 89, + chart_name: null + } + expect(StatsService.getRawDataForChartName(mockStat)).toBe(mockStat.raw_data); + }); + + it('should return `No` is the raw_data is 0', () => { + let mockStat = { + raw_data: 0 + } + expect(StatsService.getRawDataForChartName(mockStat)).toBe('No'); }) }) -}) \ No newline at end of file +}); \ No newline at end of file From 544a9baa9283849970bc96c3f4b1dd2c2a2534a4 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 27 Mar 2017 22:26:36 -0500 Subject: [PATCH 85/99] Update some docs. --- CONTRIBUTING.md | 3 +++ README.md | 4 +++- .../index/static/client/src/components/utils/stats.service.js | 2 +- .../static/client/src/components/utils/stats.service.spec.js | 4 ++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52e2c80..2ce08fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,9 @@ ####Guidelines - Always checkout a branch for developing. Never push to master or dev. - Write tests for all code written. +- Use the appropriate coding standard for the code you are writing. +- Backend is written in Python - use [PEP8](https://www.python.org/dev/peps/pep-0008/) +- Frontend is written in ES6 - use [AngularJS styleguide](https://github.com/toddmotto/angular-styleguide) - Merging into master or dev requires a pull request, code review, and approval by a contributor. - After pull request is approved, the creator of the pull request will complete the merge unless otherwise noted. diff --git a/README.md b/README.md index f0729b1..a96e4e0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Repository Health Project for CSCI 4900 -This repository holds the proof of concept for the repository health and sustainability project for CSCI 4900 at the Univeristy of Nebraska at Omaha. This repository will hold the backend and frontend source code to extract data from Github and ghtorrent and prodvide statistics about a selected repository. Description of the backend and frontend source are provided. +This repository holds the proof of concept for the repository health and sustainability project for CSCI 4900 at the University of Nebraska at Omaha. This repository will hold the backend and frontend source code to extract data from Github and ghtorrent and provide statistics about a selected repository. Description of the backend and frontend source are provided. + +This project is not meant to be in production. Charts for the user interface are not implemented yet, so arrays of integers are displayed where charts will be placed in the future. ## Backend The Django web framework is used in the project to leverage quick development and the third party packages available. Python requirements are kept in the requirements.txt file, and this file is generated using `pip freeze > requirements.txt`. diff --git a/repo_health/index/static/client/src/components/utils/stats.service.js b/repo_health/index/static/client/src/components/utils/stats.service.js index bd70242..0755013 100644 --- a/repo_health/index/static/client/src/components/utils/stats.service.js +++ b/repo_health/index/static/client/src/components/utils/stats.service.js @@ -7,7 +7,7 @@ * Author(s) of this file: * J.Harding * -* This is the base controller for the components to hold some commone methods. +* This is the stats service. */ /** diff --git a/repo_health/index/static/client/src/components/utils/stats.service.spec.js b/repo_health/index/static/client/src/components/utils/stats.service.spec.js index e7d2106..8fc801a 100644 --- a/repo_health/index/static/client/src/components/utils/stats.service.spec.js +++ b/repo_health/index/static/client/src/components/utils/stats.service.spec.js @@ -1,5 +1,5 @@ /* -* issue-stats.spec.js - (C) Copyright - 2017 +* stats.service.spec.js - (C) Copyright - 2017 * This software is copyrighted to contributors listed in CONTRIBUTIONS.md. * * SPDX-License-Identifier: MIT @@ -7,7 +7,7 @@ * Author(s) of this file: * J.Harding * -* This is the test file for the issue stats component +* This is the test file for the stats service. */ const module = angular.mock.module; From dccdb75a4bf1e514e8652e96569f880e2be2d7e6 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Mon, 27 Mar 2017 22:31:28 -0500 Subject: [PATCH 86/99] Clean up commented code. --- .../client/src/components/repo-details/repo-details.component.js | 1 - 1 file changed, 1 deletion(-) diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js index 7123942..952dd61 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.component.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.component.js @@ -31,7 +31,6 @@ const repoDetailsComponent = { $onInit() { if (this.detailsUrl) { - // this.getStatsForUrl(this.detailsUrl); this.StatsService.getStatsForUrl(this.detailsUrl).then(stats => { this.stats = stats; this.loadingStats = false; From e2399a41b9e645f8976233d54fbf4b479f95c12b Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Tue, 28 Mar 2017 18:20:24 -0500 Subject: [PATCH 87/99] Few things from the code review. --- .../issue-stats/issue-stats.component.js | 2 +- .../issue-stats/issue-stats.spec.js | 38 ++-- .../pull-req-stats/pull-req-stats.spec.js | 10 +- .../repo-details/repo-details.spec.js | 162 +++++++++--------- .../index/static/client/src/main.module.js | 5 +- 5 files changed, 95 insertions(+), 122 deletions(-) diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js index db48a13..3a2bf42 100644 --- a/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.component.js @@ -20,7 +20,7 @@ const issueStatsComponent = { controller: class issueStatsComponent { stats = null; loadingStats = true; - loadingMsg = "Loading issue stats..."; + loadingMsg = 'Loading issue stats...'; numOfStatsSections = 0; constructor( $http, $state, StatsService ) { diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js index 852b2a4..5a1930c 100644 --- a/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js @@ -13,19 +13,10 @@ const module = angular.mock.module; describe('Issue Stats', () => { - beforeEach(module( 'repo-health', 'components.issue-stats' - ), ($provide) => { - $provide.provider('StatsService', () => { - return { - then: () => { - return "Mock"; - } - }; - }) - }); + )); describe('IssueStatsComponent', () => { let $componentController, $httpBackend, $apiUrl; @@ -36,28 +27,29 @@ describe('Issue Stats', () => { $httpBackend = $injector.get('$httpBackend'); $apiUrl = $injector.get('$apiUrl'); getIssueStatsUrl = `${$apiUrl}/${jasmine.any(Number)}/issues`; - controller = $componentController('issueStats', null, {issueStatsUrl: getIssueStatsUrl}); + controller = $componentController('issueStats', null, { + issueStatsUrl: getIssueStatsUrl + }); $httpBackend.when('GET', getIssueStatsUrl).respond(200, {metrics: [{ ordering: 1 }]}); })); afterEach(() => { - $httpBackend.verifyNoOutstandingExpectation(); - $httpBackend.verifyNoOutstandingRequest(); + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); }); describe('constructor', () => { - - it('should setup the controller', () => { - expect(controller).toBeDefined(); - }); - - it('should make a request to get the stats in the $onInit method', () => { - $httpBackend.expectGET(getIssueStatsUrl) - controller.$onInit(); - $httpBackend.flush(); - }) + it('should setup the controller', () => { + expect(controller).toBeDefined(); + }); + + it('should make a request to get the stats in the $onInit method', () => { + $httpBackend.expectGET(getIssueStatsUrl) + controller.$onInit(); + $httpBackend.flush(); + }) }); }); }); \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js index 009ee08..7188745 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js @@ -17,15 +17,7 @@ describe('Pull Req Stats', () => { beforeEach(module( 'repo-health', 'components.pull-req-stats' - ), ($provide) => { - $provide.provider('StatsService', () => { - return { - then: () => { - return "Mock"; - } - }; - }) - }); + )); describe('PullReqStatsController', () => { let $componentController, $httpBackend, $apiUrl; diff --git a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js index 6083b1e..7218ed5 100644 --- a/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js +++ b/repo_health/index/static/client/src/components/repo-details/repo-details.spec.js @@ -13,100 +13,92 @@ const module = angular.mock.module; describe('Repo Details', () => { - let $httpBackend; - let $apiUrl, getStatsReqUrl, getDetailsUrl; - - beforeEach(module( - 'repo-health', - 'components.repo-details', - ), ($provide) => { - $provide.provider('StatsService', () => { - return { - then: () => { - return "Mock"; - } - }; - }) - }); - beforeEach(inject(($injector) => { - $httpBackend = $injector.get("$httpBackend"); - $apiUrl = $injector.get('$apiUrl'); - getStatsReqUrl = `${$apiUrl}?name=cakephp&owner__login=cakephp`; - getDetailsUrl = `${$apiUrl}/${jasmine.any(Number)}`; + let $httpBackend; + let $apiUrl, getStatsReqUrl, getDetailsUrl; + + beforeEach(module( + 'repo-health', + 'components.repo-details', + )); + + beforeEach(inject(($injector) => { + $httpBackend = $injector.get("$httpBackend"); + $apiUrl = $injector.get('$apiUrl'); + getStatsReqUrl = `${$apiUrl}?name=cakephp&owner__login=cakephp`; + getDetailsUrl = `${$apiUrl}/${jasmine.any(Number)}`; + })); + + afterEach(() => { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + describe('RepoDetailsController', () => { + let $componentController; + let controller; + + beforeEach(inject(($injector) => { + $componentController = $injector.get('$componentController'); + controller = $componentController('repoDetails', null, { + detailsUrl: getDetailsUrl, + stats: [] + }); + $httpBackend.when('GET', getDetailsUrl).respond(200, { + metrics: [{ + ordering: 1 + },{ + ordering: 2 + }] + }); })); - afterEach(() => { - $httpBackend.verifyNoOutstandingExpectation(); - $httpBackend.verifyNoOutstandingRequest(); + describe('constructor', () => { + it('should setup the controller', () => { + expect(controller).toBeDefined(); + expect(controller.loadingStats).toBeTruthy(); + }); + + it('should request the details in the $onInit method', () => { + $httpBackend.expectGET(getDetailsUrl); + controller.$onInit(); + $httpBackend.flush(); + }); }); + }); - describe('RepoDetailsController', () => { - let $componentController; - let controller; - - beforeEach(inject(($injector) => { - $componentController = $injector.get('$componentController'); - controller = $componentController('repoDetails', null, { - detailsUrl: getDetailsUrl, - stats: [] - }); - $httpBackend.when('GET', getDetailsUrl).respond(200, { - metrics: [{ - ordering: 1 - },{ - ordering: 2 - }] - }); - })); - - describe('constructor', () => { - it('should setup the controller', () => { - expect(controller).toBeDefined(); - expect(controller.loadingStats).toBeTruthy(); - }); - - it('should request the details in the $onInit method', () => { - $httpBackend.expectGET(getDetailsUrl); - controller.$onInit(); - $httpBackend.flush(); - }); - }); - }); + describe('RepoDetailsService', () => { + let RepoDetailsService; - describe('RepoDetailsService', () => { - let RepoDetailsService; - - beforeEach(inject(($injector) => { - RepoDetailsService = $injector.get('RepoDetailsService'); - })); - - describe('getNameAndOwnerFromUrl', () => { - it('should return name and owner', () => { - expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name/repo')).toEqual({ - name: 'repo', - owner__login: 'name' - }); - }); - - it('should return undefined', () => { - expect(RepoDetailsService.getNameAndOwnerFromUrl()).toBeUndefined(); - expect(RepoDetailsService.getNameAndOwnerFromUrl('not a url')).toBeUndefined(); - expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name')).toBeUndefined(); - }); + beforeEach(inject(($injector) => { + RepoDetailsService = $injector.get('RepoDetailsService'); + })); + + describe('getNameAndOwnerFromUrl', () => { + it('should return name and owner', () => { + expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name/repo')).toEqual({ + name: 'repo', + owner__login: 'name' }); + }); - describe('getStatsUrls', () => { - beforeEach(() => { - $httpBackend.when('GET', getStatsReqUrl).respond(200, {repo_details_url: 'cakephp', pr_stats_url: 15}); - }); + it('should return undefined', () => { + expect(RepoDetailsService.getNameAndOwnerFromUrl()).toBeUndefined(); + expect(RepoDetailsService.getNameAndOwnerFromUrl('not a url')).toBeUndefined(); + expect(RepoDetailsService.getNameAndOwnerFromUrl('https://github.com/name')).toBeUndefined(); + }); + }); - it('should make a request to get the urls', () => { - $httpBackend.expectGET(getStatsReqUrl); - RepoDetailsService.getStatsUrls({name: 'cakephp', owner__login: 'cakephp'}); - $httpBackend.flush(); + describe('getStatsUrls', () => { + beforeEach(() => { + $httpBackend.when('GET', getStatsReqUrl).respond(200, {repo_details_url: 'cakephp', pr_stats_url: 15}); + }); - }); - }); + it('should make a request to get the urls', () => { + $httpBackend.expectGET(getStatsReqUrl); + RepoDetailsService.getStatsUrls({name: 'cakephp', owner__login: 'cakephp'}); + $httpBackend.flush(); + }); }); + }); }); \ No newline at end of file diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index 98ac1d2..a56d015 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -41,7 +41,7 @@ export const main = angular.module('repo-health', [ resolve: { statsUrls: (RepoDetailsService, $stateParams, $state) => { return RepoDetailsService.getStatsUrls($stateParams) - .then(resp => {return resp;}, () => { return {error:true}}); + .then(resp => {return resp;}, () => { return { error:true } }); } }, views: { @@ -49,17 +49,14 @@ export const main = angular.module('repo-health', [ resolve: { detailsUrl: (statsUrls) => { return statsUrls['repo_details_url']; } }, - controllerAs: '$ctrl', template: '', }, 'pull-req-stats': { - controllerAs: '$ctrl', resolve: { prStatsUrl: (statsUrls) => { return statsUrls['pr_stats_url']; } }, template: '' }, 'issue-stats': { - controllerAs: '$ctrl', template: '', resolve: { issueStatsUrl: (statsUrls) => { return statsUrls['issue_stats_url']; } From 241c29eec7aeb78dd797d5876beebfeace1a8865 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Tue, 28 Mar 2017 18:27:37 -0500 Subject: [PATCH 88/99] Bunch of indentation fixes. --- .../pull-req-stats/pull-req-stats.spec.js | 23 ++++---- .../src/components/utils/stats.service.js | 46 ++++++++-------- .../index/static/client/src/main.module.js | 54 ++++++++++--------- 3 files changed, 62 insertions(+), 61 deletions(-) diff --git a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js index 7188745..b3b6943 100644 --- a/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js +++ b/repo_health/index/static/client/src/components/pull-req-stats/pull-req-stats.spec.js @@ -32,26 +32,25 @@ describe('Pull Req Stats', () => { prStatsUrl: getPrStatsUrl }); $httpBackend.when('GET', getPrStatsUrl).respond(200, {metrics: [{ - ordering: 0 + ordering: 0 }]}); })); afterEach(() => { - $httpBackend.verifyNoOutstandingExpectation(); - $httpBackend.verifyNoOutstandingRequest(); + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); }); describe('constructor', () => { + it('should setup the controller', () => { + expect(controller).toBeDefined(); + }); - it('should setup the controller', () => { - expect(controller).toBeDefined(); - }); - - it('should make a request to get the stats in the $onInit method', () => { - $httpBackend.expectGET(getPrStatsUrl) - controller.$onInit(); - $httpBackend.flush(); - }) + it('should make a request to get the stats in the $onInit method', () => { + $httpBackend.expectGET(getPrStatsUrl) + controller.$onInit(); + $httpBackend.flush(); + }) }); }); }); \ No newline at end of file diff --git a/repo_health/index/static/client/src/components/utils/stats.service.js b/repo_health/index/static/client/src/components/utils/stats.service.js index 0755013..d702ab5 100644 --- a/repo_health/index/static/client/src/components/utils/stats.service.js +++ b/repo_health/index/static/client/src/components/utils/stats.service.js @@ -19,33 +19,33 @@ const chartNameEnum = { class StatsService { - constructor ( $http, $filter ) { - Object.assign( this, { $http, $filter} ) - } + constructor ( $http, $filter ) { + Object.assign( this, { $http, $filter} ) + } /** - * @description Returns an array of indices to enable iteration over a range in a template - * @param statsLength - * @returns {[*]} - */ - getRangeForSections(statsLength) { - return [...Array(Math.floor(statsLength / 2)).keys()]; - } + * @description Returns an array of indices to enable iteration over a range in a template + * @param statsLength + * @returns {[*]} + */ + getRangeForSections(statsLength) { + return [...Array(Math.floor(statsLength / 2)).keys()]; + } - /** - * @description Returns the raw data for the metric based on the chart name - * @param stat - * @returns {*|string} - */ - getRawDataForChartName(stat) { - let rawData = stat.raw_data; - switch ( stat.chart_name ) { - case chartNameEnum.dateChart: - rawData = this.$filter('date')(rawData); - break; - } - return rawData || 'No'; + /** + * @description Returns the raw data for the metric based on the chart name + * @param stat + * @returns {*|string} + */ + getRawDataForChartName(stat) { + let rawData = stat.raw_data; + switch ( stat.chart_name ) { + case chartNameEnum.dateChart: + rawData = this.$filter('date')(rawData); + break; } + return rawData || 'No'; + } /** * @description Makes a get request to the given url. diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index a56d015..eafc7eb 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -6,8 +6,9 @@ * * Author(s) of this file: * @bparish628 +* J. Harding * -* This is where the angular app gets bootstraped. +* This is where the angular app gets bootstrapped. * It will set up all the global configuration. */ @@ -37,33 +38,34 @@ export const main = angular.module('repo-health', [ $locationProvider.hashPrefix(''); $urlRouterProvider.otherwise('/search'); $stateProvider.state('repo-health', { - url: '/repo-health/:owner__login/:name', - resolve: { - statsUrls: (RepoDetailsService, $stateParams, $state) => { - return RepoDetailsService.getStatsUrls($stateParams) - .then(resp => {return resp;}, () => { return { error:true } }); - } + url: '/repo-health/:owner__login/:name', + resolve: { + statsUrls: (RepoDetailsService, $stateParams, $state) => { + return RepoDetailsService.getStatsUrls($stateParams) + .then(resp => {return resp;}, () => { return { error:true } }); + } + }, + views: { + 'repo-details': { + resolve: { + detailsUrl: (statsUrls) => { return statsUrls['repo_details_url']; } + }, + template: '', + }, + 'pull-req-stats': { + resolve: { + prStatsUrl: (statsUrls) => { return statsUrls['pr_stats_url']; } + }, + template: '' }, - views: { - 'repo-details': { - resolve: { - detailsUrl: (statsUrls) => { return statsUrls['repo_details_url']; } - }, - template: '', - }, - 'pull-req-stats': { - resolve: { prStatsUrl: (statsUrls) => { return statsUrls['pr_stats_url']; } - }, - template: '' - }, - 'issue-stats': { - template: '', - resolve: { - issueStatsUrl: (statsUrls) => { return statsUrls['issue_stats_url']; } - } - } + 'issue-stats': { + template: '', + resolve: { + issueStatsUrl: (statsUrls) => { return statsUrls['issue_stats_url']; } + } } - }) + } + }); // Set-up themes $mdThemingProvider.theme('error').backgroundPalette('red').dark(); From 7a6c71d18be6c6f4c5a123687315d4240e03c50f Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 29 Mar 2017 01:20:41 -0500 Subject: [PATCH 89/99] Finished up the docker instance --- docker/Dockerfile | 24 ++++++++++++------------ docker/docker-compose.yml | 22 ++++++++++++++++++---- docker/init_db.sh | 5 ----- 3 files changed, 30 insertions(+), 21 deletions(-) delete mode 100644 docker/init_db.sh diff --git a/docker/Dockerfile b/docker/Dockerfile index 31bbe76..a51ac6e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -4,21 +4,21 @@ LABEL Description="This image supplies the server needed for repo-health." # Setting up database - RUN apt-get update && apt-get install -y \ - curl - RUN curl -O https://ghtstorage.blob.core.windows.net/downloads/msr14-mysql.gz - RUN gzip -d msr14-mysql.gz - COPY init_db.sh /www/ - RUN chmod +x /www/init_db.sh && /www/init_db.sh - + RUN apt-get update && apt-get install -y curl + RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - + RUN apt-get install -y nodejs RUN mkdir /www + WORKDIR /www - COPY ../requirements.txt /www/ + COPY requirements.txt /www/ RUN pip install -r requirements.txt - COPY ../. /www/ + COPY /repo_health/. /www/repo_health + COPY local_settings.py /www/repo_health + COPY manage.py /www/ WORKDIR repo_health/index/static - RUN npm install && npm run dist - RUN python manage.py migrate - + RUN npm install && npm run dist EXPOSE 8080 + + WORKDIR /www + CMD ["python", "manage.py"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index f312e9c..07e4afd 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,13 +1,27 @@ version: '2' services: - db: - image: mysql + + database: + image: mysql:5.5 + container_name: repo-health-db + command: mysqld --user=root --verbose + ports: + - "3306:3306" + environment: + MYSQL_BASE: "msr14" + MYSQL_USER: "msr14" + MYSQL_PASSWORD: "msr14" + MYSQL_ROOT_PASSWORD: "password" + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" + web: build: . - command: python manage.py runserver + image: repo-health + container_name: repo-health + # command: python manage.py runserver volumes: - .:/www ports: - "8080:8080" depends_on: - - db + - database diff --git a/docker/init_db.sh b/docker/init_db.sh deleted file mode 100644 index 5a3b8a2..0000000 --- a/docker/init_db.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# /usr/bin/mysqld_safe & -# sleep 5 -# mysql -u root -e "CREATE DATABASE msr14" -# mysql -u root msr14 < /www/msr14-mysql.sql From f95969206b91826b5a474f2064c180651b5e4d2d Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 29 Mar 2017 01:38:04 -0500 Subject: [PATCH 90/99] Cleaned up files and add documentation --- docker/Dockerfile => Dockerfile | 18 +++++++++--------- README.md | 6 ++++++ .../docker-compose.yml => docker-compose.yml | 14 +++++++------- docker/clean.sh | 5 +++++ docker/database/Dockerfile | 13 +++++++++++++ docker/database/create_db.sql | 9 +++++++++ docker/runserver.sh | 19 +++++++++++++++++++ 7 files changed, 68 insertions(+), 16 deletions(-) rename docker/Dockerfile => Dockerfile (65%) rename docker/docker-compose.yml => docker-compose.yml (68%) create mode 100755 docker/clean.sh create mode 100644 docker/database/Dockerfile create mode 100644 docker/database/create_db.sql create mode 100755 docker/runserver.sh diff --git a/docker/Dockerfile b/Dockerfile similarity index 65% rename from docker/Dockerfile rename to Dockerfile index a51ac6e..b90a7b7 100644 --- a/docker/Dockerfile +++ b/Dockerfile @@ -1,24 +1,24 @@ FROM python:3.6 ENV PYTHONUNBUFFERED 1 - ENTRYPOINT ["repo-health"] LABEL Description="This image supplies the server needed for repo-health." # Setting up database - RUN apt-get update && apt-get install -y curl + RUN apt-get update && apt-get install -y curl netcat RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - RUN apt-get install -y nodejs RUN mkdir /www - WORKDIR /www + COPY requirements.txt /www/ RUN pip install -r requirements.txt - COPY /repo_health/. /www/repo_health - COPY local_settings.py /www/repo_health - COPY manage.py /www/ + COPY . /www WORKDIR repo_health/index/static RUN npm install && npm run dist - EXPOSE 8080 - WORKDIR /www - CMD ["python", "manage.py"] + + EXPOSE 8000 + + COPY docker/runserver.sh /runserver.sh + CMD ["/runserver.sh"] + diff --git a/README.md b/README.md index 4995e63..081aa26 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,12 @@ Production database is configured in a similar fashion, but the project is not r ## Development setup +### Using Docker +This was tested using v1.12.6 of [Docker](https://docs.docker.com/engine/installation/linux/ubuntu/) and v1.11.2 of [Docker Compose](https://docs.docker.com/compose/install/). Any version below these are untested. +To deploy this application in a docker instance go to the root of this repository and run `docker-compose up`. This will run through the configurations +of our project and create a working copy. This process takes a couple of minutes. Once it is complete, just head to [localhost:8000](http://localhost:8000) to view +this application. + ### Backend Configuration Developers develop on many projects, and each project has it's own dependancies or deps. For this reason, a virtual environment is created on the developer's machine in order to isolate Python dependancies between projects. diff --git a/docker/docker-compose.yml b/docker-compose.yml similarity index 68% rename from docker/docker-compose.yml rename to docker-compose.yml index 07e4afd..2e5b351 100644 --- a/docker/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,11 @@ version: '2' services: - database: - image: mysql:5.5 - container_name: repo-health-db + build: ./docker/database + restart: always command: mysqld --user=root --verbose + volumes: + - /var/lib/mysql ports: - "3306:3306" environment: @@ -16,12 +17,11 @@ web: build: . - image: repo-health - container_name: repo-health - # command: python manage.py runserver volumes: - .:/www ports: - - "8080:8080" + - "8000:8000" + links: + - database depends_on: - database diff --git a/docker/clean.sh b/docker/clean.sh new file mode 100755 index 0000000..a4fb557 --- /dev/null +++ b/docker/clean.sh @@ -0,0 +1,5 @@ +docker stop $(docker ps -a -q) +sleep 1 +docker rm $(docker ps -a -q) +sleep 1 +docker rmi $(docker images -a -q) \ No newline at end of file diff --git a/docker/database/Dockerfile b/docker/database/Dockerfile new file mode 100644 index 0000000..3e7f153 --- /dev/null +++ b/docker/database/Dockerfile @@ -0,0 +1,13 @@ +FROM mysql:5.5 + +RUN mkdir /data +WORKDIR /data + +RUN apt-get update && apt-get install -y curl sed +RUN curl -O https://ghtstorage.blob.core.windows.net/downloads/msr14-mysql.gz +RUN gzip -d msr14-mysql.gz +RUN echo 'USE msr14;' | cat - msr14-mysql > temp && mv temp msr14-mysql +RUN mv msr14-mysql /docker-entrypoint-initdb.d/msr-mysql.sql +COPY create_db.sql /docker-entrypoint-initdb.d/ + +CMD ["/usr/bin/mysqld"] \ No newline at end of file diff --git a/docker/database/create_db.sql b/docker/database/create_db.sql new file mode 100644 index 0000000..f605ef0 --- /dev/null +++ b/docker/database/create_db.sql @@ -0,0 +1,9 @@ +create database msr14; + +GRANT SELECT, INSERT, DELETE, UPDATE ON msr14.* TO 'msr14'@'%'; +GRANT SELECT, INSERT, DELETE, UPDATE ON msr14.* TO 'msr14'@'localhost'; + +GRANT ALL ON *.* to msr14@localhost IDENTIFIED BY 'msr14'; +GRANT ALL ON *.* to msr14@'%' IDENTIFIED BY 'msr14'; + +FLUSH PRIVILEGES; \ No newline at end of file diff --git a/docker/runserver.sh b/docker/runserver.sh new file mode 100755 index 0000000..6b67e3d --- /dev/null +++ b/docker/runserver.sh @@ -0,0 +1,19 @@ +#!/bin/bash +echo "DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'msr14', + 'USER': 'msr14', + 'PASSWORD': 'msr14', + 'HOST': 'database', + 'PORT': '3306'}}" > repo_health/local_settings.py + +until nc -z -v -w30 'database' 3306 +do + echo "Waiting for connection to database..." + # wait for 7 seconds before checking if DB is up + sleep 7 +done + +python manage.py migrate +python manage.py runserver 0.0.0.0:8000 \ No newline at end of file From a82d5958388aa6ce2c70f51b854116fe7d0f6a98 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 29 Mar 2017 15:45:38 -0500 Subject: [PATCH 91/99] Created Use Case document This includes our use case of allowing a project lead to determine what libraries to use within the project. --- docs/Use Case.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/Use Case.md diff --git a/docs/Use Case.md b/docs/Use Case.md new file mode 100644 index 0000000..15d547b --- /dev/null +++ b/docs/Use Case.md @@ -0,0 +1,22 @@ +# Use Case + +**Title:** Determining the health of a Github repository + +**Primary Actor:** Project Leader + +**Goal in Context:** The project lead is able to access if an open source project is healthly enough for its company's standards to incorporate into their product. + +**Stakeholders:** +* Project Lead: To understand if software is apporiate to incorporate into their own product +* Developer: To clearly gauge if a piece of software will need to be maintained by them or if it's reliable +* Manager: To access the longevity of this project with regards to dependencies + +**Preconditions:** +* Metrics for a healthy repository are already defined +* The repositories to be compared are already picked out + +**Main Success Scenario:** Project lead understands the metrics presented and makes an accurate decision on if the software should be incoporated + +**Failed End Conditions:** Project lead recieves little to no information on the health of the chosen repository. + +**Trigger:** Project lead is assigned to a brand new project and needs to access what libraries and dependencies should be used From 1e5ee5744fd001d948a1328b70e13394bcf6e7b9 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 29 Mar 2017 15:51:17 -0500 Subject: [PATCH 92/99] Added comments describing whats happening --- Dockerfile | 4 +++- docker/clean.sh | 3 +++ docker/runserver.sh | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b90a7b7..2860359 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ ENV PYTHONUNBUFFERED 1 LABEL Description="This image supplies the server needed for repo-health." - # Setting up database + # installing dependencies such as curl, node, and netcat RUN apt-get update && apt-get install -y curl netcat RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - RUN apt-get install -y nodejs @@ -13,12 +13,14 @@ RUN pip install -r requirements.txt COPY . /www + # Building the UI WORKDIR repo_health/index/static RUN npm install && npm run dist WORKDIR /www EXPOSE 8000 + # Adding start script COPY docker/runserver.sh /runserver.sh CMD ["/runserver.sh"] diff --git a/docker/clean.sh b/docker/clean.sh index a4fb557..e7e726c 100755 --- a/docker/clean.sh +++ b/docker/clean.sh @@ -1,3 +1,6 @@ +#!/bin/bash +# Stops and removes all docker containers and images + docker stop $(docker ps -a -q) sleep 1 docker rm $(docker ps -a -q) diff --git a/docker/runserver.sh b/docker/runserver.sh index 6b67e3d..564629d 100755 --- a/docker/runserver.sh +++ b/docker/runserver.sh @@ -1,4 +1,6 @@ #!/bin/bash + +# Create the local_settings.py to connect to the docker mysql echo "DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', @@ -8,6 +10,7 @@ echo "DATABASES = { 'HOST': 'database', 'PORT': '3306'}}" > repo_health/local_settings.py +# Check if the database is done running its init scripts until nc -z -v -w30 'database' 3306 do echo "Waiting for connection to database..." @@ -15,5 +18,6 @@ do sleep 7 done +# Migrate and start the server python manage.py migrate python manage.py runserver 0.0.0.0:8000 \ No newline at end of file From 834f159eaf9706997e7fdbe6de17c2f6d0a007e1 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 29 Mar 2017 15:52:15 -0500 Subject: [PATCH 93/99] Added comments to mysql dockerfile (forgot to save this file) --- docker/database/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/database/Dockerfile b/docker/database/Dockerfile index 3e7f153..f879b39 100644 --- a/docker/database/Dockerfile +++ b/docker/database/Dockerfile @@ -3,6 +3,7 @@ FROM mysql:5.5 RUN mkdir /data WORKDIR /data +# Install MSR14 database and add a custom sql file to be ran on initialization. RUN apt-get update && apt-get install -y curl sed RUN curl -O https://ghtstorage.blob.core.windows.net/downloads/msr14-mysql.gz RUN gzip -d msr14-mysql.gz From 1e6a43ac8ca21a8a7514f19adbbca055443f2666 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 29 Mar 2017 18:47:24 -0500 Subject: [PATCH 94/99] Updated spelling errors --- docs/Use Case.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/Use Case.md b/docs/Use Case.md index 15d547b..8154500 100644 --- a/docs/Use Case.md +++ b/docs/Use Case.md @@ -4,10 +4,10 @@ **Primary Actor:** Project Leader -**Goal in Context:** The project lead is able to access if an open source project is healthly enough for its company's standards to incorporate into their product. +**Goal in Context:** The project lead is able to assess if an open source project is healthly enough for its company's standards to incorporate into their product **Stakeholders:** -* Project Lead: To understand if software is apporiate to incorporate into their own product +* Project Lead: To understand if software is appropriate to incorporate into their own product * Developer: To clearly gauge if a piece of software will need to be maintained by them or if it's reliable * Manager: To access the longevity of this project with regards to dependencies @@ -17,6 +17,6 @@ **Main Success Scenario:** Project lead understands the metrics presented and makes an accurate decision on if the software should be incoporated -**Failed End Conditions:** Project lead recieves little to no information on the health of the chosen repository. +**Failed End Conditions:** Project lead receives little to no information on the health of the chosen repository -**Trigger:** Project lead is assigned to a brand new project and needs to access what libraries and dependencies should be used +**Trigger:** Project lead is assigned to a brand new project and needs to assess what libraries and dependencies should be used From 2bb10d16a96dc67b0cf323b956125cf127d0eb42 Mon Sep 17 00:00:00 2001 From: Benjamin Parish Date: Wed, 29 Mar 2017 18:48:07 -0500 Subject: [PATCH 95/99] Removed extra word --- docs/Use Case.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Use Case.md b/docs/Use Case.md index 8154500..1e072b1 100644 --- a/docs/Use Case.md +++ b/docs/Use Case.md @@ -15,7 +15,7 @@ * Metrics for a healthy repository are already defined * The repositories to be compared are already picked out -**Main Success Scenario:** Project lead understands the metrics presented and makes an accurate decision on if the software should be incoporated +**Main Success Scenario:** Project lead understands the metrics presented and makes an accurate decision if the software should be incoporated **Failed End Conditions:** Project lead receives little to no information on the health of the chosen repository From 54670c0ab28f50abd93b53a7f09e0297b4bc3607 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Tue, 28 Mar 2017 19:38:02 -0500 Subject: [PATCH 96/99] Remove chart js for now. Some whitespace changes. --- .../src/components/issue-stats/issue-stats.spec.js | 2 +- repo_health/index/static/client/src/main.module.js | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js b/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js index 5a1930c..efcfc67 100644 --- a/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js +++ b/repo_health/index/static/client/src/components/issue-stats/issue-stats.spec.js @@ -31,7 +31,7 @@ describe('Issue Stats', () => { issueStatsUrl: getIssueStatsUrl }); $httpBackend.when('GET', getIssueStatsUrl).respond(200, {metrics: [{ - ordering: 1 + ordering: 1 }]}); })); diff --git a/repo_health/index/static/client/src/main.module.js b/repo_health/index/static/client/src/main.module.js index eafc7eb..6aef679 100644 --- a/repo_health/index/static/client/src/main.module.js +++ b/repo_health/index/static/client/src/main.module.js @@ -15,7 +15,6 @@ import angular from 'angular'; import ngMaterial from 'angular-material'; import uiRouter from 'angular-ui-router'; -import 'angular-chart.js'; import resources from './resources'; import components from 'components/components.module.js'; import mainComponent from './main.component'; @@ -28,21 +27,21 @@ export const main = angular.module('repo-health', [ uiRouter, ngMaterial, components, - resources, - 'chart.js' + resources ]) .component('main', mainComponent) .service('StatsService', StatsService) .config(($locationProvider, $urlRouterProvider, $mdThemingProvider, $stateProvider) => { 'ngInject'; + $locationProvider.hashPrefix(''); $urlRouterProvider.otherwise('/search'); $stateProvider.state('repo-health', { url: '/repo-health/:owner__login/:name', resolve: { statsUrls: (RepoDetailsService, $stateParams, $state) => { - return RepoDetailsService.getStatsUrls($stateParams) - .then(resp => {return resp;}, () => { return { error:true } }); + return RepoDetailsService.getStatsUrls($stateParams) + .then(resp => { return resp; }, () => { return { error: true } }); } }, views: { @@ -71,7 +70,7 @@ export const main = angular.module('repo-health', [ $mdThemingProvider.theme('error').backgroundPalette('red').dark(); $mdThemingProvider.theme('default') - .primaryPalette('blue') + .primaryPalette('light-blue') .accentPalette('orange') .backgroundPalette('blue-grey'); }) From 95e91d4da6bde41927bc7c88020cb18ac90557c2 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Tue, 28 Mar 2017 21:52:24 -0500 Subject: [PATCH 97/99] C/S diagram update. --- docs/Client - Server Workflow.pdf | Bin 22220 -> 25390 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/Client - Server Workflow.pdf b/docs/Client - Server Workflow.pdf index f1e413aa1b19f38915340e22c643d6348180bb22..52105157d12d21773b404ab6ac89d247197ebf3c 100644 GIT binary patch delta 18379 zcmY(qV|3o%6ZYE}jjcPjZ8Wx%CTVQj{5JL-+qN1uZfx6XY$pw#-}66fopsKez4yG{ zGi!b3x@IP7AZmvo;#&YtE)H&CVMJFq7jt8KM6c`%|4ElK;a}SypICkn3MS#(?7e)-wb7Zy!=0H z1$Dwjl)ilwLFU)`mBc-X;w$$OLeYB#(dL>7a=J@QxHr8`p_c06J z|F*x=S0->q(l?4SlufSeSB**1lm0C4-J@KT(~~M7EM!k)7toU*j(dUKWt6K6;Xbi^ z%yswKmh_Rr^R_;yI~PZgS5{465JQt~lZQKuEEgM07&IE^4N}0Hi2r;pgcQym1vI#U zX#hS!*#ASA9r%`pgq&Drg!OJkq_#J`Og6(Rj0_GqoZJ!n;G{F0<;-8a2e%2_G@HFV zAmkV5zYrQrha%z;5E?0jum;&dCzr)1NbUcHLm?>FxEG8;%!Vw?x*NEy@#bfF3H_>O z5H2E49JTcd`pFhtCOSlRD;@Bwvl}s!DgPYdYF?F4tOmHe9bGU`|zCxq(nruBid|I zy@}qDrx9f$+Y}Gg|_!f=*FG&Mv3b@iycR4yJA|w@J*|Kxfns z7s$s*1u@vfObEHNR~qb73GwXG>Komlhlp*wAAoB;P7O=1LSb9lr_xiU)uBoT+#iZ* z%bU=}m5-s;1cJ)`@}tR$+ms_Z=u55x!lKD`fY ziz}H8?@2AIvV`9KvKcHyJj92kG8XhGzbGN-fT7s{=Y_Ly6Io%UN@Wh(aOiGX$TD&`kOMv9(lniS87 z5P>;(!xPNAog>CsS)kfK?RLF<85D32!tqI zxp^I<72}zY_Ew;VQuKDvS_H!^3TyQZJJg**#dm*Edj+|%FWdP<93er<=Th<=aVL`| zLvm@#=G1B$tyi^vJgPKAruwT!rC2k2eNP?*yp3SMAL;Jz3a)Z7}Ax>0MqNspv6$s=+7x`4HF}vlDyd8>XR&i`08(rkF$HFOR0TH=#!dzL)htI#=erNt+`AV)Vf+t8(n!n*lxn3E%wW2W zgkxHO(`MGYwE^cM8b`4Mw~yWsf-3R1dRh0u+$`uAjp>-5*dA3!C#7RaP|eur&DDbox=OzeRj>1Q;X>arW?ys|aUQ-%eU+X*P!1}URA*6xwb?je@7pfqm!DcT z_EG#bgt@?JHAX?2+xB;wvkO9&8D|@dwPF6p@0TAhsJ7;R8gKLe(#hMJuP@tNDLI|x zuSJBZ&Y<(ph&CP6f0f6(j4k+L&w3&sUkBx8+O^2$j(L72Q-A_sm67BXu*UA4kp_4t zBsm6D*}0ojT;&`nZ@piS!1?{Oy?shhq=?#tp*C7OYM66j#BESHcxzrfiGG(^jvYjW zv=(X__+EZJ9KI8$y~JyT(`%C zX??oc3LbIT@9+okwY>hK{Mn{>e0EBkurlH7POnwDWaYc$d1N&4chLoqHpa(O$E)!_ zwF`YAw^|{=m$x-zt6|s+q#x~1dx}#7I4_FFn8|S>Mj`|Qumwog;MFV%K*Ej2$&aMq zXAlx1&1`%-z2Sqkd?ZQ1CKY0jm(KV|h0%bDxO=oJ4&g1(Y1Q0o8s%ymL*zY^yO%v^ z8S0O{3RR3AUZ_9jz}dFPVc(x8HO=JBm=uQ`$lzmX0>>FJsS(W0{{ux`!h{FQ5^6tR z`e@r_NXBB6zVwv?85|sfjb_s=W*es>Qyxf5PA11+fCnMjfJdTDhGv4G%9h&u6VkQq ziJeKgll}(qp^GQ&K|??qOZbz`^>^U}(&;!TA08c}j4eU141LLKc#oo$H4fh!57Tyr z%@GBIrlDLUBBgg(p~|FSAT2PJ{IZf_?D|c>FayO+hWI%5_8Z6P+HYbHfogQAj;FWB zE%GJsYKGXTh1BSw!swSx?PerRG~pt%;pB5|w7L?&%uMN|PnZrPidK3zAa$8YFXmX! zRugyg8fP+EI#sPSA46kwy6%p*CtcW474|OLT6dugL06suEhWU>0j*`$6pol=h_8gM z>~BMkx(>1xxFy2*v12I117!QKF+~SjQ*G$uGj|sZ72qu+rVy)H;Acr2=^gL&fFq!4 z=>82=L{VT0-I!@CIU#)ICQx`TZ0f-d{E314JSO@!^PtiR(b5YJ(7$q> zkMjq`(MFK;S+6#K52;c!tx?vWxw7w=kc9@iasP_n%*Sg8FQLYR#09^KOornj=sr)( zyu?vDSde~Zf2$V}bmB92TbvR}MLAw;pnOmvR}K)(tu{XY5RTFJ7?@dBJ^cM1Cj|Nt z!lQ>Pdts&5PdJy8+}+ryq$wr=4donKNU|UU=XnVKffQD-w5eDux0u6?wV#ZG(o+V+ z4h$}&V##Xjyavme(4?3_kLQmrymX~{!J@zVA`s|*Rpdocq;>Etj1onRlK4`rz!>WK zg%Z1n^Xygq%Ynxfc>mNM1cqq~P))_w!PfF|c}O){Sl!~mM#N^FDCUx`_gdWj!b%lc zG1Oy|Z%3d4V_3cnhz?S1SoRXsa~J^$$YK7A@*eN)4%))s4dgLBE|a$Xps7}WZ*TOz znx%36n`Dx&n5#ef;Zu}}5zZobd^k+(re&sq*Ls&fT-&WpNUc7cvbsR7A!22H;iX5W z$p!hWJFX$S{^|aEKB1*2EG7th@tjYCBT`(*is+P7-%szHl_Ph}9(|3iA*ck%>Wp7+ zbTj7ZFyYbX?%bo#@VpdE&O=4DkSfiK(O9xrDK{Godry0Vagg5-6ionC<|=X)ok@3n z8EQGV9<;Bxv{!5wo@BBL_;nb;^9`#}k)?43t^!|V&-4<@&;;5*(ll-U06kHqb<&7~ zId@JdWI1qh6oqHrAZu+kmwF0N&Z{~Ws3)s_r6&;ZSrdV+QqpfeY??)GEaUkCYoVSF z(RQ$k5NxQY2vMb;L2|xVZe&H&bFji;B5eM?(UwF9`NjViDFmV$$27G8cYJP{qHNL; zmUN-cLQWh6wG;w>Op0ub%0(rlps12QZLjJ3b8^IBiCOAcgV8UG&4wu;^cYlRLs@ca za*Eqnq)mQ6z)%X`jL2M5IL;iJ5kwYLrM?h7`KP%)UbjA;_;<*%RD(!l{K9F|gk7*A zC5P(|9NFDUb@xuU%Aoy)c;o5@M&{|SFlKSKMzdO#>K_`*78wTzYt`nSmdn%^_7VGA)?bqA@!md7&0sa2{O0o(*fZPC^?s zN#rbCBLI?aJES81uioSSa6POzUngQ=w3domGaczP=T{u9)Ezwqo`Cnezwtc6)ihm4Pb&{9?jZcL|<4h-o>Gy))kjB@KXwp;N9p8ac{Z{>}K8e^A|` z)#FT~Z2dW}1Zh`P(oH$E6EA6U6Q#q3>&ahOT422gf#C$5<3CDYzVDY!$$};ajpk3+ zj*(MVQF}IewF8Iq=>@L2i^_^ohH4x?1tfQs=@%jk)v=UyT&V?NhV!||Zvu6qmvD`! zRa4!c1(bZtTxqBNUr6^Q-~PXhPO-qOSOYXyxN}4EKmJwMvNWf+k(MN8H$e~@*eCo~ zjlDd%@-?0X6U+TK8}mAqP#`k;P7S2qAaN5Q9MYVm_V0xq4xCl#!MQ2tKCU}PegT6Y zhZWNIS^0y0Hm7_3xX}2^D))=I5Wkn2`l!VBMFxKp;}W43~%u`N5v2y?j)k|6wjnOQZF8B9--jlq*KE3w*${ zxLF`N1`tmzn@hrP@khWptu2#_#pW!~WcQRlYpP{wEN*e_%V!UU)X#wHv&zr-TSU+t zcAfc&Wd1nOaVl<_{DBxkRD%WR0Jjz~55et9+ypbJZQ-Nv`2Dbhy6Yp7 zJ4;jkYuYH+sy(|6xm&^1OlvU#AhQL@Hse3O>hh((IJQ6Qkm;v;j(sIm(%A%?75@t_ zgwps8s$va)_4n+j%0zAJ5bj*M^ z%aW0pN4dLXd6*XihfNO*efBd|$sKgW((R>J)aPdw5$Q}|Kg56S<5T@bl~R2y67YV# z^H_}=XpAQ8{WdtRH`%y#P`Pw4Sq|J2B9IL&EOD2Ab1!hj46}%mQw&;xl-*> zBPH=k#rO7osy|WZ+nY_ss$^2>Bi4*1w<1d>Cs&b~yrRU}qqiVX@>PA^16nX5<5bP{ zbhYK5!M~a815r8Et&%HVlr6Pg$<%jz|0P_>WW4f{d%D7B1qqy(_IuxtN^wrqw)BY= z;X&J}(yR81gV|P3>d1@@J8Jn>&`Ar$rpKcdmuzc}G*@Qvx)Mo=d}|JipZlD>CGKIo z+xqGp@|=UsMg%R7i@J^`x`9ef%LKMIyKG4I*0D&EhpN zM2iBQ99&E^MnpBH>KoKC3~uY}8AbDbEC|fn`nI(JRi^m;30(A%i|yF+#s%bf4aTpsx^7v){vk!%=fQzu9#F+Sl9_t z(KKCL^|*7nC@-z0Vp=~n*E*3%dCGaN{Ej1Q(g+WuMM3JARmw8+Vb1OL=ha~U9qjCJo1Jvn))%^4aA!dUj5tsqb6?jf zeFel_TpQ{X7FIrm^sgvW*G=?%u3wYnHNxo;PcXGXEXuf9b4J^hXe6v+x9f0Yyjnop zG}h`UquLEv+q5`hK-Eo{G?|C;r7GLm2i-DA?g^&;#twk!AQhKT7=WTHe!~#twJQ}v zMUjVvXn#%0k&7!b#%9lcCSl)VKPqLc(n(*WM_#1!#gos6bu54dg#QLbi~$O> z1RR=2#$?lI!!D4Yg&T0ks7DBCq9(t?q=w!8LGL6UEsxO{>7T~ z^}b|8AB?#2Uj>{JxWy6;C!lx>obAye?W+h#GHiJk*!2*kaTJKT5k&6lVxNa16(AsH zG0$qL=xSYZ?z?S%ldo@3u59)!#|9p^L)4Z7=X4Zn?35MZ^q z{H~${d&j3{;Ju~shi7sYM4#&2?VoNC1pmZ(RdshDtQ8li1xAvOyDtBTSP2=Kc8lW! zWbz3d5JMwhHmIQ!ofwV&~J z#%teLu=b5e`+7;^-M+hE_@^+VX-=xpqJW4qJFbe70_acRs7T0;Gef^k1aTqX^Akl$ zN9H>bYkJDgfn!31B)tjoeWqp8mACe45)3`HvnalLYN9?2g72(yGp=!mv!DL@ZCpW% zqJKN`;5spx->r1)gmKn4)d0Rr`@eg~C2j`r9&mW~5G)=)9$>0^t*KOMz$uZ06d1HC zQMj|4`O-s@mk2eI|NVNv==BX|C7LgnoDPmA%X4-j>$e3favgO}m>c2&3U5YdIY*fV z=+s{ri%s?$aNR-@AT)VwNB);=E=Yh=<;b*7+1OPe>RFYXpKKBmJqrk_2`qBh0oOxy zrlOOKtn^CVjckB5A#QE{OAe04y6&mlmoX&VEoJ=>L;6%K{j77&NycAZ_~UOr_u$|q z7H)p>lGLk1@JKH8Slpj9%j^+%^MsFqdyYq}%f9=NdO|*H<=|Rz?-hFii-G=+S+w(f z`qgrKg;zF#lV*aoLSWiGN-Z6gE_?1Uae<&XDv2jb9q(K)6aqzFKRYgiyGiW`3-*;z z2OB4W@D_Kdpm@>toOQ)crYs+W`&`4!dZod_dO^fFHSAw{i7}sie*;TQBc~Xn4grc1 zSIw%xj3!<{h?{2+uSS5Z@`rjGhs|w2Lfqzl_Dh{*TzkK}_W1|0M{u1$@+h3GV z2@*}p&&yxY#9$ivKl793UdlH~_jm@FgXbsF3~Yo;6qiGG;_XRex4nb*gxVKz)L#5; z2TOcaX${fEwp&2!Tm^Li$H>c8+wQ-GtCQ5_I+vc{*MB00`=5w^{(ZiMe|CJN|I4wP z-2Pt7;{wUko7k$z7?9Tq^HW@-TpLa2(Q>cVvKbR_KmBp?>Cgu0a z?*SqW6XY*C%fz#Yiqs%?wehc$E_shkCU{|X(l{L%qs4{5nwKGu@`uirh{mxP2{BhM zG`aw3KRZ3RP9nS>KEayyHwoo1*&`OBXFM4gfuEbXnSNAJXrquqUYzqc_t6dqO}AUI zvkE=7&tAR1_tav#go#4DpC%3to6dUz$R`TA*+FsOBqR8Tja{6LkYB1Ne+HqYw{BK= zGUH^wxwRbd`}Tc2#j)0<7(?Bkg*eB}o4LBq0csjTKGX)G#g&T!=0?ZG0S#7<-Z=>u z_b1`-CBB!an$Z~P6@1g4(_;khmM5=FS|#twbYK4qecT_63UVA-N!T&=!hTpu!U;nV zMe1b*%W@$9wlinDIkA!ihIj+WpYcnno3UuiYAzX|s0oSCWL5gJx>D^U_GxJ3fiCKS zZk>|EB9IfIb4!rMH5n_?w*2H;eDwF4$Md1yg;aC0`>)3h|rnFbe z_=D$L$fVwF%^q(fyEAM&MnsqGz;zSq8L|Y_7!xNp_5FkpPj>ua`Ye)6`LpU&BI;Y8 zx2+4{;-eNL~aPFEJbyFU+`~_0srx{daDjqR@li zhntNcdI#h7eH*8Q{=XJu9K$*jmOGeAIHn`Hkfb5pu?!Ug25x`n+=~f6k>Ksr+7BmS zqlA8GHT{ZY=z!tDR#(*a(B6X8%*!ut!`a15I%ncgv`E~{bH|^m$aJN8_9fWDSq~@> zuyoMNi!ig@2>C|BDZc;u^})>Ck83Vyo<9-A1sCETZzUB2ERd(;N_sTNWAd;wJabP( z{fg#C*~DWPKv383DfW`C|ED{N<02NA`!3^7z1$JujzD&P(gX(ICvusUC?#+W)l@`z z#Y1VL7dH^qUVrodVASH=&OxrfE3-Tyl7HYEZO%jtB%3zcYMfBXsp3g;-9t(#_+t9Z zFLa<}L=dHBq;3|5z@3pNJ;Cde?@XW*+~rMN|KWCWot=xtweU#6vqA%_L#GIIfBCBi zi`v7lnC6M#QALMHrQa~$6$+Kfet(YyUZyZMi(0mIAOK+jsp!0P5!$`lK}C4t^EefN z7^6rdw18q_{?C3VHV5yyId3k|2nK!DnNij+6lI8?zV%@LfxFrwJ~zDdc%)Q)rR#}M3LbcZP6pAA7m7Mfowof77cA?G&62{z`|FR_S6d+VHPYFWd7xuInEsTv2(Je zQMSagG#&Qd^_#|_bz|j6VaRi`YOEWNjrDc13eSD>(@pnkInyW{MtAO_A?k#At}IzzhAfq@51Vo z{=s#7X^9u&UEMdO+=h}F?D7qu#R@4@7Epkn$>Gw-k+P2BKBa{3;&-9Y^uv`r- z7Zg|+X|2-od@msMb~~F{Wo{8Uvs6#TolDwv(Mi4{!@c@xRr@(>UffmKVn{_rzN-a^ z>SwOWtcRYa$A+SN&P(oWGnw284dEf0q5cLB19lV?z23Ui@GrBKT(5x!TCk)uW0dL5 zA5e6H&)Qa?F0txZq^{@&;@)?();_2XY#C(^jR^8at+6ncj2xPY3 z39HWE!x;!Gi54DRXH=43ritz?5|v^avfwAMJ4N$op{~qYABnR=)8gFyBV}^_nNfjf z5H2?4I9Y+_l`p0Y4NY!l-M(DYN{T{Y=5xtAQ{UMXfApb?^FcTv{yoAlQrK(zP3VF7 z;XQANui+^>&WYSlYp$K522+y#n9%)Lk2#roj0y`#YTM>|!?LrI3$L$tFwHGRxC?BE zj%vPKHSqmsRvML1aj1W=QcxyigT9YEv05yC5<>zXCyEcm&WwZBzVu3Gbd#%1%VD-6 zqHb4zDZ7gRSz5V4foOaF0lFl7w?mT9w9x--Evdur7ev41?7DqR@98ojOxI zeL+C!vL6EqYpoK8p3o3x>tG&N7sL(!(psO_qb2r@>!hv4s%`0+I?jlQ2V)9rtq>bC zR|`uH@3yv3GW1W~^3_tPxM9{EjU%0966qhevjYCOlKLwl5|xf56$awhqVNHE&@7^K zs%QZ`wAjiS2ZdW}<_~C>qN7$RF-u(Na-)FNW;AiLy;M~R)YsO-ltkYa_9r|0hpzgo zW@5kDr+*6^&MzpwE-xOG&{skdSZlgAn|mAWXPA*$9_-2*%pF|~sl)~Fie=MfENY5+H+V&(UWG(yKv1EE=g;e^Q{87HRZ^6Ls8FaW9_4a{3a#7A~nHdB$ zIX$xdI)kFsLs9rB-iC07MCW+d)L93UBo>yzEDfb$`a0@jC;r0oC~_jObw~m7X9Mj5 z2;9cYA@V{eYWN{_CR+9@nde+#}!qHVH zC}js~d*E9>!Hy@31^4DuGy|1p4%(4Zg25h&hmicq)+_vRchM(}7?VZ;Z1(c0S0Oc2 z*rc)y<-_-jtGOwr(-2+yNRs*w4PWXdST;KB!MpL)i#!mK7Gt9-DI7gFh2S<~Y)7T_ zos?^kC}x6%)+`>?upL1G~-pxXv z#!U2d*|@)@$9w5$fg4`Usb}sBZ?kjn2{+oOc=Icooj{blt6KQ zoK5?Q)WN#p<&24Y63`#fm%9O4u?&AGY)TX);i&r~1+1gw8&EzlQ$47c;mJDgWI4^* z^NF{|skx&0%G-pL5Paa>s28|ZgngpdZL|<{W5wDtFG~%s9$#hGrKQ0pr{IU?krSR@ z?8rb12&dORe;q;KQC2Y%d&(wCx6b!l_?jQ}7u1VhQTfd#8XzykRb-=4$clCQNqe4c zAmyjpukWuKhaP)bj;Gyd+*LT!gI8fv9F;&Xb^7;EN=!v+^l_M31d<}PDL*T|I@_4S zaz*e6pL=UNQa?)BLRmN?cjPadA5v-m*{^jlQSGKGyY<|aW)k>4vx#BtkELQe-k04d zh#9TFn9qo1<3MHxx)VpMY9=zgrRqCSS7uTaS~YeHkeZ;2)sMpge?45UvNAGv+LUNu8l!n2m{x)IuO)^2R15FaAP^Q zLKTypvfq)qD!DxK_t?&V)`H){7n?Pt`-NgIR#?u{h}|ym%A=Opz19n#tw){cphI@2}6E^v0^dAsfSWHoefBz4B0o! za?W0i-~cx&ekG!LfEdOmiP7+>-~+2`2bzLPJ<02#dj2S{Ab0PjlDoq+B606> z4J7rXOAb~&o|x(05G;-=c_E{W&>C_AbUZ!)aO>KMLxfd*Xjsbe{iL-LyK3ONQQ}M0 zw+{|IV``(%V?+Wa8)BMkRM!&qi90-H?&vD^OVr^7?U8C)bJ%b6r=ua!?%6}WJ$P{+ zW28Oz;Si<2bD%iDVa|p=W{11>x7RVox}PYC4UG#lLSRnjF*cgjZ~hpZoB|iSf%v;z zfbl2P2`^>a8p26dvc}Cj`Ip!CX6vJJfNr!1`vt{wq zm^_Z3AhPnffY(JQh`GdS(IP_Km&8Z~yrU&zJUHcK${2`giLh7ECZE?jE^ybnmf%pH zi%}Rs-=Ne%$Gj06moo3V1*UXISA}LE&v4HNE8hG#%XMK|`i;&r^;wlx> z&bZ?wzqcj7H)2(~lMP?Fqs!xbN}>LMR?BqURkx&ov#haFr!n6^{uoEUFIx_P@;jde z#z4zS)_1Nvl*Sv0#BHambf;fWD*}Zp_Ju2;W%Y$3351L0IfL--MyBO6-s3|$c>#W< z@>LHqpQ&j~4p(Ihi|GXay+ly_9Hph?7PGNdHu(~M4N-bG}dEN%$NfmY3` zCH1CdUgULxSN;GL2?KHZ@{JN8_Dp8OSnRs4Xw_2Yy3QuyH|;#McWC3`>TdMV#=Nv5 z?mM05u55&5;~=D|c!;ChHLLQHR9i z=8J}bf!r3$b>HcPQ_{sFt#JX3nTywX^M)PUq;kQV5MrhJs1$018aXJA4=EI-BfT$JFtJ>E6rysb=#NA1t91sz3#}q4xie)xa+J>*qiROyzmLNws z^M=?Yu%syZ6oZBKr7DlKjQMn6==G+8DwSL@;~JIP___7g>ZOu>Fzl9fIAk0Ytf$UN3M9r5N zZDu#PXeJ?qy;mt^JTV^2)eaWqf+1>y!711B;H9TEl9TmO{1sa#XBMLjZtGDn6C@&0Vz^0BsdIW#$X#Yww zwT5mj`JXcmODfTHr4XX!>&<)lSM**(2iNaBisoQ!K&_lbiYS(8E`JInjuXEzn_v{$ zUgF#`hNt9g>V8HV*2d}3?YeK_e83}cn}c?wh;n>P224q-p!nWa4@$Pu;OZ+Ywc)j# zE2D>xF=+tv;NjRfzUEy7FrQ|?ekx4vnq6e(=eW&BgBm%v1FF&RznLcZDbY138Q-77 zHmLbdW~@2#jH(imy zpr=9{3Y&W~W9MZ-bPY^2iOneV($RQtT44zy(q)|9$_^>pdIoW~l`CvtPg_>KUs=UB zIA;lqT`b73#Hf>W8ClxjC+4;vv$bs$IKH>VPQHvmF%L0n*?C%avodoXj-St?t_E#< z9}>%zy6=fD83ZLlu?L}379rGED#^kE^f#&V5)-*?!An@SMVHFr-4U@Cyc^iBZ28)f<SmPwjI_f&@`D*Mb9GYmrOSIa%u4m{WYddWruj?I54 zD7&^xld5nz{9xT3-EM2XCcE%rbgx>$l(D!=ZAH2sB}+=XE6pTTD{qDyDurB3e1T&f za`{iZ=KkUL{t~2Nwf*jUrMamp)MKwVR9T-CN!hbIB{Rmfql>^#(y z7_iZ&rvB>|t^d^2-3F=1WQ8OZ?H|BGlUcc{pqo?#3_ps#Qwqc|dRR;X)&~SAV{ODg z`y^ue0{`ke7?jDCi=(2&ZcOGc0r|a&r3R-H`Dh9k95*}~ZmFJGucV~AfmI(|ei#(_ ztCn9+RJPw{!LE+`_HJ-3f;64@sekyzVF|~h!xoRBqLc{Tb5`8+{PXW#N{c25< zx#daIOBajMGxWe{hD$Ac3(Ge};)2$|%lN%dnv_|gz$YDw50%PnIsK5Ag$R*dn1@dE z9!VHY6Jj_eZSc?eztC-C6f7$cexcCL|NI~JAO8iUGPP;`dk6ErZRLEg-L!Sb{643N z(`jB+w=(Na%X<08korMAX)kR7iF8!|qgX7*Dq=pFDRM$kQFWpaS|38P)vQ)H9!-54x&wUDQzK=@T>?!0?F}=6OV= zSFmfsB{ig`J#{hFYmw)-(UAPf^VJF4cjgs-Nr`(qQ=l8v2Kl|}fAbZ-qGbk%2xy@A zev;2B8=zuGaO{jgpA*TdX*=owf1I5W<8q|Zr$l)oIIqzRJM9n}Bj{z9j->?@mw1tI z^H-mvdq774{_6#NM`U}g=|8AloI}`)>s6<9;nEYNo85X-7;Gih3d7#%9pEr;mL#Vp z9yHy08kR)s_b;173{05V)0YQK;{tHszIY)+9atwm3sL!>HIy#yFUSBJ|LUg@k$0JW25&iOT#7q`Vkn42 z!8!d*?UU$!fx7XYdwcxCf{$?LLQO&Yf_JGlN$Wj!0AIF_PAd1pdCIir>zpXc>WKCT}b+-32`zT|9b-IAW<6+<*7{zRn{G=G=j z6NqrV(Sk4q_!7V4u^L6(GT9*IHRD`3Y35)YD)bSI!n0Bs)cw z<*+=Z1x9S0)I7_DypfJXmHWwz)wiDkBYw5r0r#0q&c;OExW9bIR!OZT`}swa*(+-d z_80#t)P1#e`>L7E$m?9TNq$>GfA1cX2WFQI+e#U-rL(7&+`k>ZX`=+U18~fiG)5P zy8q9CPs~C<8p@}Z&LLwA#yXTSo??D!{J;1A0x;!Q z{>7;kQMBNYqDIPULHOsb>*c2B)$GxkwG~U>@odKvE7r{jPwd%hPN)V}8Ub#TavE+`JK0$Bluc9 zieWmb(cWw9{PB?G+GGC^A?iH*DZ4tc0nimbg|W*uhZAy;*X)_4jJ0;i*uHMk!TQqF zJr!4&<#rZa9T&n5qx(-Qi9?_u6NLXxn{)hW&QcQ+|gi zuh;4=sK=|nl&>(4XFdn`e^`TFa`VHk7i_I!rm1ZO-kfbipcTUsD_fG$60u6+d1-2& z2Le@NjelOcX#7&MiJ` zbr6)Lh)Rs2KkrC54pS&`1&|x>p$$@J4ajmwb@Dl(SXLyf!&cZ%M^eLqBXd(ajD>`wKhsiUD$OY(Q6 zVUT(Fu#QGxAjmK3iWB<>0s(K`XcM>5N|oM?ce*0v4U4n(rY%y8nKjf{T7V zUGB}>%-l;ONwf zqstRe2tVwqX(rJ3#Z3y9U>%AT$XHQtj|P!V*eXv{Rb`Col-xJi2!zNU3BMdmYm0hZ z7V$W_HU7);zfXM$tgzd)6)vZ~bl$Du5qVtdNKD5Wy66NRKsGahOe0`e8s$}l`l8te z+VN!CU-rVLZE1{H|8A&*M(5I=$eh*KWw0s9G!LN)i`eCgsyUuLo3_uMv7 zSslWv4h!fMl#)*Cpllnvh#L5lH8n?nM3?yOhN-{qr>Qx;P~*RFQB>3a^D9Dat)jAB zp1EWKPE#*VvF?m`&THu8HrxZ~6wz9)mFg&`g1yVu8=8iGj=Y)s<}xrmiO8x&N*j9A^?Yi``UX(ekQH!L_ zz|zy3mteh3M1DE{(Uw7r55Voz{wA79Wc&mPt>HG zREqoLI=o&kO4G{IGi>fSTh@{~>9<@yepY`ad!IVV-;h{BsX2`UL=1a6eXeO5IsA(| z0(>4WX_w>bguSkJFJE6e1~$oWw8jT4ypOL)Pc6q6Y6#lLbb9ouiE$#4IjyaT@rdh| z!wmZNb*+w%;1`th3rNVcKY!*w!Q#KP&J?rV2mB~#iN5X%8XD>i(>S=AnZbMbDpA1N z^htIk!8-e9k!wZl@iiIKcn#Vdh{Rh+D#WO!)hLnqcVl>l zSWE`X#xoR5!7&hMS{}0BkZ<{lUik5Y8Q~DYq8vTuN-DPU20n;S52@8ViU>AX-i&5O zkkRDZxRya};;Q9O+*_WT-u@l0sAs`H@L$ZeF=wFZQD*c>;Eo{thdmfl)v38ebN*zC zzYp8m@m|rWkHtUaRthfqTuvIxLzGX&W7bvk4D@2FLpQZFE9{qWT22Cy9BD_4~3XVE{bFQ zDED64g}77O%f$Se+D6%WKp=6)+}uLo2sQdfVHN$P(8|e{hKSGKa{7iRrdux@8;Wdo z^@TiaBPjpTpCy8r8}m2x5wD9lIXm)*m)eO~)p>zLy)FMHok*+((b{LDps(T8-|58% zqb=xtHGmaAOpyA3WQxy~+3ZFuLeE6x8@G^+cZqHdHLX1Z($g=3&blg5(H!a@qcbN) z&8N0O=m-6z=wbtj6@!B}Wu_cME?cP}<6g~ZaoOQh+? zsUIyj(uUN|7F9yG%r(``Z`gdy`059E@wiq9*nr%I4mODc_fOaXjR7St0()(Fa4E!&w z6|wi0Vi+&xw6M1*w)zvdY6xy_q_O;x)gCHVi-DzzSq{&B6XSExX-eVxGTOs|EWC7b z0ic%uq*{l(PeM(cS3SYUSb1`0e)@rPnk7=B!lLEO_b@q^L6l(!-{ktISE=%DmYHxF zA6o_g-Q9EsYfOaB%OuamuzE*)L4w!|FIYPTbZU(z@v6A65`qnN5}b{qu?N9`4k5Il8S1)YKc_)M-c>t6+k4VmLCpW1jVG22)0lQ+Oi7SWpZ_;3a+necGg&pcC|V{K9YQ{Ed{N_qx|4@t|FlYG2VxwSEbsiyhr7 z>orYmxJ_?|qgVtLaN}9pm5AOsAq*ubP94l*r?W65MbwUQ?kNMwXr^{92Y)sj=fNVF zb>L^eO&+s_>7T$*rr)M=>3Lz0=+rmBI1@TsHFmcw(oE<>A{ z;t+c$n;CM;8iZV;K_($Hh<4867?qG~XUjd8NW!2dmzX+j*{*Ty{y1wLJ%7FH^L*EO zzUx`fde{5@@pJ}I%hT=D=~;e!SBpA#O0t5WHx4uKHB)1Fxj(JVHim6_A+y0pzIqCw zIxv~qr>1CJ?G#ZiJU(j>B~+ypYv1$LyWWyx*}aOGcZd6?9_kErh~`00Ll0wSYU&iT zVjo$s5%yuBf3?U5wu4b8OJLifgKv0Ma*-gNwe`5 zh9_M-Q#C(Wsrk=XiYL-f6iA(*Dt}&Ekzv!!hE+sI(#s zjDF0u`V~7~wRdo5+yTnW7_>Zh8Rz{uAIYv|zCq32jn9ZHrjK0LBPuhMB>zW+MHx#P%dcT`|4p{zI_N|aO(5dVn*~BzZ?_fvesRk!RVr{TLq(p;dYoZJYPKq&6nEDX zZy7TphRSPh`?J19Bq6mB==;5=*wGvrtn3GJVx&FQd?)ouKT;4V5d2X+Wr2bLj4GwC za`}gpCqGT~nJf{~6+eenorhi8JiBc7mOr_uobCxl z!HLT2z&3wM;&;=#o3GVtR(F2h^m;1LX`Z6V6Xx#Mgxl4y5Yx_i2lBsMXc7LDcK}=< z+MOlO4z%dH3^gVYT8_V(OFyrsCfRx8)H3>XEW92R9}+`smrzJVN!D#YCpgI`;y|p| zd5+J`q{&tv-BJGmZLztMw+2Kep?kAH$vJiqIyULaE1-NpnTjZvBlG9ugOJqRe9S*;6O9#4^PK>a}RYHMG|_ zsrAl;f@X!j&w{7vvuX2u6hClT(VUYDqtTNbAq7T{A6?|1v07=vYNINQQ|EjWA!Pbr z8rd5(`6m|G-JpnJy1~cMP9AFpW5KmF7^ywkYQZnNw66}-pmzo6lCvqxX~MU&?_`}-pO#| zCHkQ1$wm(0+LBtoQDR_#q$Wb70DX9|GV;hL{d5wAhOZ1PA1aR+hlh?Rvp6|gFsYk; z5a}bQM`k7TiV;zetUiT9S^Np5=LuDGM0;-2!L%=f6f031$M3<`$o3VpvhD>|P%~J} z9&^x2<+zAt_udb#4eQ&9>QprIUs{wwOE}B<41})+#EOSYlvMk?mjv*`VKYIeW;tX% z-7$BmE2AMF^x^g^HC1E%Bfr@TUwD3;X<`~V7(~gLDj#|J6ztr_)Sj$Q$qGaS4=l`0 zy%Db`o#=7aQ-`&7w^81^id!=)ExGK2Rw+XHhrT?d)nSw6&^pmQaZyudd`E(bJ0#A>sBhEIW{ z!T1Lq9*e{8*WqzE<2~m1f2QzwywMLrBcmV8;|az;6vh)txz038GygqP0XTmW)Eo@` h9%Se~Lm*+MX0om<3SCE{S2+u?tVuE9;5{n zAs>PejV`Oc1<#|5M8(4jF9#_1;y>%B@22j|7)^qVcDRwbXIW166n!Kyr_2}>L3dmk zmY=Z#r?pepj@peyVFbISRRlXxG-*F_aYvEm6oUu@$7{Vv6!50v0AF=*l9@x2-)L?)^m=>fcCd|Ge1_67!*Q;w`o!NKesaXgi{oYI3m@ z#_eLl5ekI;V^C$+dPD-OFeTdhh|D}s6?h2=f}zFkM(u_uv7VpyGJaVR%xV?fgGhSX zTaD{1(9NA=wY**$=al#yb6mN{8RTe<2nYZ#6%0di^9Gn9^Y8CIKPJ*+lGUM!y-p$W zl3>wKd9(@O8N{junKJT-Psj-Ln_dS0LeJ)voN;3QwTTe6=6X&{VV@6mc6UIJF;1Kx zq^JKEp?D{ZY*MTlImFg*I_R!iGrBeDNNQvT`CoQGT`*QtYmnIPJ7bU2BgYysBOJg@j24I`qNVAC_P1ijjg(p)1FL?|6LkX1$&$wEhcWupyNQd_rLW|qrQ0jzunlsr$5P5$L z<$%ZQ5bv{)ye9^pZRbr9vpp1oRaKrJF$GX9E_MJJ-9_tKNv&6I<-~Y9fEflZMi*{z zHD%2>>8-O9AffczD!^VM*%}rv#WVev*N8@?e~^8Y+yvN89}!0|gz~wRd}r*6h_5<2teP6_8nmr4|LclVBMQ~6xU~Iy3XB6fh7m;Yn3`5AKLS8#Vy-dLfhy@C%C5=U* zcduYj$5P>K{PIE_2trWZ@88cmU6%p1NRsp`g~tlb4vEaP(y`=e7P(zKNeF!i`- z#<-nd^-xl$Q!xQQQdBY@Er{tIEebu$b-kv>lE^Zlna?)`1xI-$vbe5n|1F?+BJPp8 zY&{iZD-j0<&=89~DQXf;bh{XV9t&stl z1cT)1kRqz+E`1$yH7axH%Spg>6OC;0qr^(Sx~-`JlqCc@0Xj!<$qZ}ZN4$sTj;LoN zb(`4wG!rcC;RUg$J;Eqb5urFg6J-bV~pb?;pvOHos)BST&W!II>Ro{-CM`Da_B}%y9Y%`)$V|zcr zIk`HTYKPa)Q`?N-R&68Pj<1^!cR$Wv+rW4qSo~%q$PlMDt!PSP4ARM-pn*{@qu5jZ zv`#9xb1Eo8vaVPOHJp!P`?`BNqfdQ6+Jo`tgW)|WhQ6rp2|OXhb2!d^&@oZnQLo# z{G!9UbT&0%o&2dM8BY3QtD@j@vdS6vZa(Jxpwy{KXsN>)|DKEmk%3nthde#iuZ0f% z19CHXDUM4|=N z%>leA0p$@q6LH(oEa&VmUff1U=d?Ai>a8Qa7iC)u(MIReBPMxUi_O)4^U;4+M4Qmz z3x83#{tEgzZi0)$vjy7N6|D8UJfRo9-_rM>!&Y0NLeV?=`#P3{ghbk$R^+ftK(s~>C%>+{x&%4Tp%vs_p7viW zK2yp>b8K}#g`j;>W9aaV+PRHEY>WzuNR{wFr7>xd?~I|aT5#by1{z3IXnB2Dml~l* z5n5E=S)j3iLwNMTJUsj;U3G}1cS(`R4B^}=(oMT}M4>MCY{^M!U zb4r{W*dC0v3>!_x;OB+;gi%8`PyFw|Uxr0+ln6+_BHlTq4)=<%Z4~?9{!5|R9sTDG zHhy*1bpzuDJ~Q?VhYGb&da&L;^U<{PH1yhGa|tEjR7`jr6M;oK-#=xQNF(anz*ZA? z`xoiuiCue2z7{(#kbDjvZ&&wWReIEfTo2fiVN@t@z5|9&#Ks_x+i7ZYIfN z^S1#~fA}zq)kbn(dajkba>Uzi`@eh<8UJM6*UDqk4Cm#p`?-h$jttbuRaDf6GLi2MvGgXt7JT_F4)b)4;l?fvN zRCRp}%6yAcW%7t@$pm=HAQ<)0r|<9h!6&8roE=9QKhHB%vMwdCL$L7RVP)`j5UgNj z=;dru9;{%;KB7RQ$(#I0h^!y`I$Gwc2B+&w`dO-0e!ELrWypgPdX2EZwLvgo>Vat$ zUzPk5$0(ZD&^{lIb!}~LNHUP_Fq{oQe_ge=Y^_l$^5m$TtxeyIUwx)>AEl2C56_(N zI_0#x%cMaC<#{{yPT6ta9s^>>OFi^9HZgX|1>;FQ1ItQi|B{mhXEW=vvYMU%k@inb zWZ2IYLCt~3FW%i#xJ{!Vss2doM}mU%=lq-{RJS-rVP^L-d=~o_xQjR)(FH}|``CqS zM_gtYIgcTK*SJZ%zuEbbF#-1coPOl%Z6j6`a^Mci?mz zZ;4RaYQXY13ddq0b#tSTY?cuqtTpc;A};fw$m)LB1fZy8cg$ogO7SS<2+y&qWDZC| zrV0|8Tn|m7)$u1y4lu`{ASo_7(mg`6$Lb36IBQA}9FZ|Gcp?OM-nW)8dgBb`w+!OF#hLc;C zTxR(pJuflFsilD~hi#xHnQDl@1#JkW9ae^$7-UOE_C!i1!5EaKnE9}_z1}42lPSBm zT;It6S@HHmgi9M{sk0tvPrdJbyrx+%sTCM_Y*{p8#iq#iYy%o}( zbxaWVx}RH&6u7G#GE=0?1qu1rNmTIC&wS^4VQ(&A<{23#*B8=^2npcf_=)Y)_lnfx zo1BnzZdVss=FZw}p6tllQy+Q!yu+R2SQB|+d!1k3XjpvF>V~7_c+sw8mw(qjxr;q*WCQ)g z>TlQl$?ZVpO)NjfnGaIfT(Nc_87P1N5;F^9SfCWqAM0Wold zJ$vFH?HhoK5Fl^#q`Nlh9*f)RyT|K_v$QQP-c7uXd%#1ZTl7XGa*!~7Q-ZzBMV#b7!s*Q`uZ^yW`j(9a|nQ1)Mb1M9F$d1shZ z^UR&2s_uXPMaC4Y+i98X%=1l>`irC{X zBiYM%t2@s>-*n1YVUv|djWu6{OFzx43)Ab#TL~h|6{El4wWHp;N_c8hV@(uNq^h9!p5N*9B$~UCrGv-HcE8;YrgzRnmwzv}2%p zqwHujWE!!mvz)jRRnHKMscjpI(;zVxZ*`d3jAR4uJBwtu_7>nn6o1$JWD34WFI$=; z;x5ZC7x<9_zwJfYVYaD#IZwf!mBrd?PJ1!8)+YGd_8Ytk>SVSI30TM6N^k=aM-i8F z+Fw9<#fEc~g3sA2c~OVea89UEhx_-BmtsdEE;}nhTcMoP;(=q`sy%<zgIuUA(Bf-tMc13{b$y6gz8gm!yzS(VyK4{|XN7f#RdOS~^mM zT+DgQ^LvHrJ?<=xnN!}c#pqe5bv`Ig#X z?qoliB3!mAJt{4qxG6!rXK>8v>%lqT3A((7|k4=jvMks zXJ>XihO7j7x2ly1aTUhgh|DZGfztg(A?-kR!|Qii4;W_!u?1TbA6wld5Al&9{> z;*_9}LzLBDy0$uX4@43*M;m#$#!uVeR_1SdbH6MXF<1xzJ|r!IF!LKVw_g9GgxD_6 zR2#kQeDS@L5Xk>wzB7;&WAr#Q`E32l|6=>F$~xcO<+%SU{{&v10P_soFZ`}q^4j0& zr|(Z+J`cB1(*#sDR0i;Pglhr*H~$HH;>$Ez>y z_fhT1%pme>0d|k^k?;Y+X$f^Y%`!{-?ca8RY3RT=rw+6NxbQiOR@Ul2S<${}7j%1_Ko8R9CdD^oBS8}w2xL9OEr5;{E*Pej|-9Ut*Y z`$t^@1GQhElP~RgaTl6bTSi*;7Y}1#js?*r?B@*$tYR~A1;zCno9WtSiG^n8FF(&l zT|yZ@SQ(>Xt!pynb6e{s+QveDFNsV4xB#zwRidDp?!325z z1bNQ{d2{~$m3jOXb#q?1IsRGTkrHheykv2c|DJ3v=B5YH;!V?QDR@JU2tm4)zHBE+X=;W*;=U2b+^~I7;m!?`u75O3SyE3g;*Bw~0vTOxxFgdp9;IiO*FGPQh>c%MlY$+M z6G;Mch{yAs$BG#bT#fDDCGY9bcjAh`t*i&M=F#C+>ho168|&D^l#M!|$!G7wI20{EL9uOhGEF$QOp}JvlXI6j z;1p4F&MiClHGm$^mH3dDQ~A0hKF&R>n?I%BkUkWp68TbSS=^$qW&R{5`qd7JmiWF; zr*dZ-yZ;kY-d-x$kTZei_Vy|1A1_wWIX~BZ!)Obk;v|Ez4rr}uE7kRsM)+<##+#&A zV&MDE6!jwr&FHYGeB z`MGHQpAm~ccT){A1r+)!oc6hb-Wiz52ed87Qv?tFX~#NX_l0Q!Ituw!jF4s8ft|=w zp|)uPnh?1UV06idF&gNw*pk*K!|G7GLyW_JTFYkY=dT6@r(@Ol6b@7X2pK81qp1+t zWBj-+b&OL3Y-*>}$;bAsv?FJ;j-KLC^0gkj*+YKU3nxw3JJ2PrQ;KFi+a;xbgvVd( zE`hL(aG|688M)r1G2b^e^1I8NtXzy9bB^iFkn4ySm8mdOVXV8oLYpAa@gNDtrh+A1 zYzxWa}=Nl%jl(_z1C+bfmzoL%y1q>crUpV-&NW-E(Oj=ji6NcXR&){K1 zxvt8w!xbmt)bNkm-h>)Sm?Wj<2{4}aHZX_ho|!)1$+s&6WT*$=3FsO9!VY};dO`j2 z_-LOKX=v8@MLr&137w}K2{nhji%ocPkyrRfq`@8=wq*WF#p#!52Pq=^uWxz^!wlkYWmjF@xOYX3xJrDK&6Cvr{RIBv(h_ms;~@=ZQ%T#u zw-l^8ZVx)Te$-S91HmTLvwVA_VGUDgrQxE)8nZLsWs?iOU4s41N`qdeX0&|08YHt)0VqQYpn zxxhLcHSs0toR+$&yEBLcTjM<|UDl_H!T9ZurQU%_+;1?yB;wMO+@Y*+$K8sNNM7d^ z$~+7>M#h?s1ZdH47Pe!5a;sru8=D9MoWTgAjcjWb2R%aW-0ty3*bL*D*o2js=LB5Z!7lLFtx3`8B(IIxOJ3sYQY>J3%zyW=r>?XvNI%y>L`7P$?G!riS~cJ~x= zD*C*5dCPGTo)wV}-&YB5zUizDPI z#y;xr8PGx}UQC3H1AS8`Cp89!J1JOLl3NHRXB?DEIRCuI`aZ02q3Fyk@)O@T55f@; zb~DQzPu#=S5@YVzt_oq>Jryu`l{W8&Rw7I30~4e8V1i@~7&MQ!V(A^IfAjc}z;tnZ zz48-%hoELaU)Ufd@)g`qg8gSd%h9!y*BzkZJiT5sc#ai zl(ba8?b_^amWR6=)WUi5;+m_a8C`-d;-#Y^Ock)q3h*#|B~S^ANT8m=wqk`!3f;pyv}zU=Qtz}7Mg+A2ag%#sKd-oe!H-+?XV_$t zi#&9I9M@Ig( z6pP!L^=?0AY+Z|4GDyyT*PQ=mwJ&86wrLM{gbSqYd*Z@GQ_PJ#f~F+W3#2)-KYaI& z;ThX}$-CYPG)4GOnx@8)`r)8fV_~p*lB`=@8_N>j40_20Vw~2fn{)H9Ej)Gea&uEAiyrkEHnQr zM#Tfvv$1QwJvEsZdU)fC8jb~fR$N_`e-FAAMf+p}(7$J?k(0jbmTC}jOh|S&kN=~a z3c{GDN3XUOOv0FdrFC9vL9b4U#Bxw%pn9~kIA7nud=l$f)w`D5xx$El&!(6GtCK%V4)#!b_76>n`6oBQ2&0$3{DiZ4??+;HSw zJpL;Tv{)&k5(ZcJ`1Z5d-?!{z_l`PTM0j~495^edwfq_WkCxRC_%1qp8jONZ@jgN@ zB09jkAFdMuQs~p|D(#eQ7LG2oLgVBDGwvqk9&uY3;&ZM~2N0xGaCW^ey4;y^p>{OtD{dD`_c> zEFUx4?VE2JR6Wc}c2<%~vLxN*sQws+d!LQ`{7(F5y~VfgN#of9_6ifF?ot5<8myzg}1`_Av46;ChUv6*6q~N5ujo=KR!|vHcB> z?s;iJ9$R`x9M`n&iUh~i3zZ2l3_Q~I6s2|i7NMald4+p#!58WN`7i8ni3Maz*&c8uCfiz!WJ8jFO!}IVg`To_ zJ$jvsP%>%rOfo-VuRNG4ZkBo1EbGMi8gcM&y8zb6o`2nF6;us6k1z%XVGpnYaQ?mH zc5M84Ay`;TB3hCMh&od**gEM7gt(1;wE0ZxT+GmEIsOdZH9lo2JJrFOma@OsQXW}& zI*lgX(ByUI3{|v#tjQo}u2z{Gd?+2N*|Eo( zC!XFI5D$(R^H(vWX2t`9&4hB6vacFcr)w;-o#Y_jH zw`zgH`?(X%lkEYx;smd-4a#F@7ZMQ&=4-WYI57DGraged~+YEOVNlXHB`Qc`1v zlpYbq-3V+WPJM~y5?s$h7*U&3{)nYE2mmgxT$f2cCKPk-OHq#Nvq1_m9ZtQ?jD{Vj z<7!+X_7@s(^s@_y`;C@#1c? za3{g)RFG->wHhaKcy4qR5LKW$LlJ|7_y&E71_5AsGYM_i!mJk3xO0Qn)nf51OcWa> z++?2Hh@Zo8&vEd?VexVY=rIh#hUKsKaqu`GaU1WFtE=&eFifDvYe2>f23hmbCO-W) ztShW!=}&O9Hn4?lB^~b>VyfuN^GLPQs~=*W4Apz@}Pv3=k;9;w4dBxG>X#IIj+?vNR>F#^ED}8Y$~8 zB9pk()g@h&Wgm7xzygf|c|q2QAml^oO}$R!k7m?tnVa4;D~x$e@hNfxE1dd`we~G2P47dMfIHtLnNAfH+ihfP)gThbv}8@ft=5+EpI zN%IRSAqGp4VQ97MaY9iaS2I;y@ho-$^n2M|$GItkUh8J;4q>3~FOwFg&jOZ~EwfHF zU!xx9T@Uk~dWFbw;4;5ubBv*+tu9kAdo))K+`Fox7u=)93g10+(IHGRRO7KWW;!d zCfYjLn7S@TJ)jOHkPl^-(W^Qkx<8kmO%Z|zRN9oCq?c@IeY^6d8(+5QEuH;Hv3>Bd z?O{OcY)iZTaW8(a?`Sh1oPp0_F|6fPb*=HOhq95JFI<0UkXIq&!~DHa70_1nH=yvD z8tr50GTJI(&E7OVm$70n?m`|xiDt-QimvDg6VWQ9M;a9WUC*&vq*LCGA4>4?&Sf`| zR7WSM{2uavBOe7`kpD?}vZ*_ln>Vsx{O@^Z(h0&;pT<(0M;V4!82=YUog_R3TY3uU zFX}{}S{Wuqb`;fV-ppTA9N@4}u~{#Z{b?sBEwZ;|)yT)7+kKP#^6gKjN@wztgFR&@ z>#^-i2`EY|cSz2txKCUk33)1iZ+*`9{EQ`=wd4rCwhbcfkb%CdT{4%g5|HWU+eW~1Fa1CkL zKgP+dvvh#>#Y?on-<+e>Re@Azu@6TTa-V+ODH@NuH< zA1~ND5|ny8iQ&*tE<=0?D8@EvOtw&G=rM5L3HehE>`s|qf?aeMb}%IVce=zBB`~Mp zjHVxKl$3kn*a`UO|UwcJdy|W5&Q+NKL3`ZTo#6GCsAA*xsIn@8s7TEsH*hSo6xLZQvm_ zl!t>!K0+26og6R(?g3BfOrO%LaqjQPZIBLD`g+49UeIobj!)0DCEccvN%^mRTw*@3 zBV(UP7P;Ox39u8hKAa6QfsXRvOI-n%ny1lwh*(2e#8N}ZmhB^labvT~#(E2K2XQuz8I5f>blOWI&BCYAbVVppK(n6G%|&U7@N z_$zJBzvblN!nFoO5ZhC?!(}ChOI{BhFC(aoPMoXcsZrr~%G`2w9@r@g{qG@%oq%A| zf#X5X2jHJ;4)XVtSPVb>X~$Og;2DrRuy4B=i(9qcpcHEv%f#@b9?DjxZo~!J7H@1f zQ=26ru3M}1dV{EW6a#!kD~J~-i9b?EFf0$tJEoCX1vsG{YY)_hDiYid&?oX3l{@dt zjRMICkhM{so*^*uvI?;Zl?xi}t}dV;ubUcvQd+C_IR>%0{ZhT((h|}xcdv^yi5Fs- z2HQM7eA)ec{aW&=I!%n?;{(|Fc)0$555)})W4Bw-{dSG&l_k~g*~uj%)#94UHmR8+ zkMq~bS-=B_NXjtHl=E_Fjv_qv<6zf-QD0M)0pK##Zo&5rcr!eissa^i38 zT<3?A{p_cm?ylEk&AmGM_oI$FL*O1Y?tanjbOkA2?JV_dV6dVtBq{X1@7c5d;e<=L zCye+5S?s~=WF8g029R2NgZH{6AuVQm^xuwiue|qz6(Xb{bdG1qlQvtJMGG5P`_y9z zH!gVreya0V$pD`yri4g`y=148iT9$E2%9o{cW0&U<( zaYlIg*-1lV@)KgDBjZnTWnLM&$3nnA2Ulng2K#rjn7N4KW zkAkgbIJ{Q8g@iJ8rG~&vkBouKrab`+#9YZp=69%hQkx)qMw3d6Ig!yHU%TRV3^f?0 zn0nSQu<+t0qVsS58s?~rP#M?g4EeC}@fKp#KMrcxvJq+O=b!|ezdQ`zYJ?}QXzq)4 zboS-cG&l0C3*hSmZKhG64};bUfiOXD2P^X$ypo_wGlH{gGgsOgQ8CfCZ!$o*9238` zNy-}1$ZBv#_rnDAe{cXO06jqoKbD6K=9i( zV^)cQEy7@gyZ(Z~K8Wjs%m~m_=yQ>qzQ%tPt8+;qSpRK4W=)Z%`P!CRlDHX&6z$t*c z1{buXWj@4uxwP7z*j$cknMt<4SRc#%!s{|$wch=U{+C89%@5ouh-IK6mMf(_knzsA z(O=K!F*pCml7v`TLjF-r9>03# z?cIUUI3u2-)z)rSLNPh6b{H?TC1&IxnDTxa%onzkfz8^_W)4e)>2EI{QY`(rs877H z@-YHPBrSCC8xSQjoR&9O?ih{1h6b7R+B3|`t8OUAhx3`IHNik9O}K6y9+wl%9LLr} zkdrviCt3TO8XKL7ukj{Z{tdf&_PFVQ^pxoiET&4ux1BPa3@@`ivDaFayc}5571auz ztgp9pEEF;x~xcE9@%K53f&_Tb9MIq`?}qELtQ|7#OjcegHt7d#us8=Zb_E2GC| zGNoWu16Pv$8z}ka50hZSSYZZ7qN>YGVfu_GfBZ5BK0FFSR^af$7v``t;~5PWuj@ym z^-A+Gu6gpMIN@`_dd!SQHm9|G$M7#di{|)8|H%4#c5(QZaI!(GF+vyhWFO;Xeu;-hc)(c82_Eh8l-rDo$B%Ax>BF^9 zD5K7!fBVh(Di?!;QDS>F!;E~c#hjoyZeNq|&oyRnbuUZ(CiL^CHNHZLeS3zhwXCw3q303Rg*K({H^k|*M zLi{iA4vh0*I-EcPGKn-%y?oCP@{82ts4_1a7S}fn*JI>PWmzYl?tQP{O%jQWQ_s@h zPy%J6Zc)RL>DLjk;eXk?DE+d6`v-w08fO3IYD$g5qg}r9KEO1Xdh)w+hs;n_EWXt1 zQul@(kM^G3N)Ng|ST{!B-#1#9b#$-|7-UD+KDKyA@-d6o879^;w2_ke(5HveRd`3k zcKhbf;7hG^70N!05l;65N1$k2$Xy-5cL?xVLi$ zH9;(>MPN%U3I6-4CSG)PAzx4+*`-q9Fu1I(?xw5y-VUFMj?>zscqZp(m8^elfJjzJ z%f%?Xp#iVrB0Ro@Ne;&5iuAYX3I8AD|Law|9RE%Re1UP~Ui;ZUPc4H03j~6IFcY)7 z_B=04n0&CIp(3=XOd2M?-?eza)(wtVD9b!9?7hRx3z1jkm35Hi#aai=y&Sq76s^*J zT?N+uE4KqzY{_O%v^?*|f}&BUP_L!_YFTckBUdAvA+y%y&f2tDs}oJVkp;S(ap&oP zSx^GKRbvP)3^NK49ifR*utq=cbA^6b+S!iCk$gUG88yDGVxcYL?%uzo zAL@yWTUo(y9!<@H2G>XBD^*yA2eQ&N*fjbBb2F znYQU%2T#k08Xt-J&Fdk^r+q*kxmdTh^4Un=98vicX0-Josy$(Rkuw;u79&Q~=_j+JD>kbazRsLh(&oFt@ zA&qxQqY~Yc`-FVtG8qv74SqDrI$Wtm3o~1nL6>wWg3?Ut(MYFPKOG{;GtAqsSvWA3 zl(^=r65yK9YH6bGJd8ZHQrbLSFZc7=dFR7tzonXD%`i@%7+?;QJIkV=F{h%7J7Cca zT;dee7^3f~Nk$wF)Suz5m;e1?^|Q~#t{pwDjqUW!V1QS?t6P;tKvWZEg>+FLW#FE7 z@CM#wFC<`cbJ^bC9&|+ZYAdKFi&9hz-JUs?x7I3a_r~9nNjt&0y3-3^{~dk0BiR#k zUv$IM#I%Ia1@QHn?4qkC!y)?WS&u5Gk#<4VXYRrT#{h1Ao^|qnx?^r)kl~|?hc_n& zZ}q}>E^-FyPjGfmmmcFSW)-fD@v9BiD`vi-bW^NU?Bw{z<;k&Y5^rWI+{zExLT0XO7OF@{`VL3|I;OMn3&>n@^N#M{%6d}O6ow0 z@IL}OD-U;Kl?k638y`FC|I)E>v9fdgZ;XeVgZ=+tynJl`3u9;HN<=lqHs}1`I2#)` z&;P;LdAR-$#=-l4eErX%|1%C74|`&rsi+V)8xI>hp9wdqFaqiSG(pn;1sNjzPrYN} Y{NEL;g(U(z8xIc`0u_~{vJ}Gq1N5KQ@c;k- From 7b53f0a51e9b7038ab5dcc5845685dcac33ea070 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 29 Mar 2017 22:13:38 -0500 Subject: [PATCH 98/99] DFD update. --- docs/Data Flow Diagram.pdf | Bin 10571 -> 19268 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/Data Flow Diagram.pdf b/docs/Data Flow Diagram.pdf index 7df77fb028af5006c195db3db416afaaf8141bed..a7b5892e7cd7cb767ad16c062700186900d982c5 100644 GIT binary patch delta 17875 zcmV)xK$E}AQpA=4khOm?G%_(UK0XR_baG{3Z3=jt?Y&Eu<2bHAJg-$~1L5ZTv4R@k zTMOtxp7V7M9E1LPaC`ZG;s;QcGwiVFvYdY4WOo@1Q4~dicmuSPY5zWK`%kiN`tkXP z*@cKd&OrO41z^uK>F0B@IT5gD!1_e+4E+4#-|aT~_y7NE`u~6a_#ZTnM)`O97tG`w z4MzW^|L^f%9wKz$#8@M@y6OM;1*iZ0bNZ{@{y#_4NqjqI^ks_u57AE9?-DPV=?i8~ zEZB#v>zBa}P3iIFVa~hhqk4KLZ>JAeCR^PUCflGe{g_g2KMkfU^i$h?0BoxC`gA3f z1|>T~wOx%>u3>*9`fay)!+&W{XgzWRD&IucT)!Wn&1M&Sqs?#M=E@5y-{W{eU3=cj zH?}^u;RC(0Eo-qlUsiCg1Li zKm!`Gy(2v(5@zD>?KamSYf^io_PyE_JPKDrgKAq1L(6|-{6v3l({XeyVur0dtuM{S zCh8vY^yB*#34Z;G(1UFav?6%l2HHZ?ZBMtQJ+IIwqD3n7fe2_TMP0E3^yT;!>78nu ze|z_~w6hnxQY7EI|9p$1D1tAjrJhluC$wLqMH(9Nw6}dKFuG~Pgxj? zuNY~_?5BTBH?)ry@qumYhfY55_jU4X{k*XDB4VY1WyFU}G$s1#^v?9rvYXmVVB18{ zE*E&3`zanEnsP2vq~&jSMZ7z`LUMeCR?xK-;HOj|2f&=MQRb(ge4)cXqGPGymIWcp zgl-MWj;Ltn-$-AZpwJ$^XQ+7ejco>WH~luGrx|}6n!j(aNRSWQ7r%)nNf3>=XQ(}c z`qDG$ZVSXYNo*f+k{8H2(SLi9u3MXT?bX6AY)slynwVK7;h98VEI`Ysm<1y{>1{7A zP}_kYp1U?2Zkw(_gsyxQ)Iq2v_Nd0Xh6$h4)X5N>v^kpQ{ z5s7~%&97DXtJ;JWXgARtwSInTSoM)XpggT-LkggfpJ|&*w1(7S0a<3}plgtlXc*fz zA)a0N8Ha^48K0|7GBAXtXwSlLjq~C(Hj6HV+_;P6l14QnLwKI&=~i0O$o!a|?#%q0 z3%oS1U*B`Y_d9wJ%dXsk9_XjP;?on$eF1;|zaY8xI=PUhQ3X#Ry8~hHHHZp>l9I~M zM0yZQL&!rHA`?sgZv1wk)9)p*gf76}-7|&8ceh`^J8hQGzq@6iecr+lWcb#HesLE8 z?MAxZIDtIo!e@``SIHS>v-E5*Oww{lO5abV;xCam$cOD;+s_bKa>D2H{cnua43>W) z*P%P{A6@FVU!YnIYg8v%u1JmRS472)v&(4hz&buKQ9M?P8veK`8KywhG?q*a8yk8i z8%bgZ=mS=&fz@E+0(1c^9Jf_cA!xA5sBDS>*!r4ecl>v2!h9P*gU?GKJz_5)KbUXB zbZD?-&MHmM_!1YCs&-@I-WRp1q*{L!YgOx6JlJ{TQw?7Vy-1sD!o)rHsV$k*Z0giT zaJDj4akO0%>~@Zbbo*Z;Qk7{5krG(*JaL1MHW{K?u?o3Nsc-UjTifR!o_`WO2@ugr zVik?~fO?h)10iw3_OJ|~Hpz^Z)zYxe(&I3}$n3&d5pXZ@`MiFq+L91EAo+i#y>_GB zff<&AXhO3h`c8jxZB$2J*!hGtqQ8*=H2_!IYk{dkDs>>~g;0Se-ezB!HP9M^>p2)t z`=3Cg+lt^9k0z)wz(UW9EIr{4B9H_*6Cs8<$MVzN{uILBD0t%)amrx!B2Lpur8yh{r@JIXX2SXOZ4j^o&I<>AOkJFywMWOuxTN9xo0c}?$ zFu$pod9Ok$w1?4H>K&SXgx-|5oOWVgv6KtX*QO zEw7`qGf1?_&sNtoiPhC(8?f@wepYV1wl2K&l59O9c#z`S6{sdnMxLjB$>Y6#HOj#f z4su6$0@1QbOZ=M2VnJq`w$14P=BeB1=H;?R?A4y{^0=Q?rQm-VfnF!DW^`;A4YOg? zK;ELs^!dRqDyGg)UcA}DnSQZwMqDQgrx(P9v_`CgCKP32HTM@I^kuQJp?-hLg*8s= z*Z3MT){yQ#WQ_J>qdTO=TLvBYYI_g>)~o=A1ihD)G5RDCjSLYPsL2Xo=G$ZC@#bfM zZ3d2f`4kK@G=S~XGwC^_{#ovWUsnGt2Fg{`KYr3B%CTMmbl4aT=RYMf z$J2rsX5-Mt$(2H6S^PkzQxWRZUUv_XB5OVBcxiWH|<#=-(=Sy&-@1&2Joe^Loh^+eTsi=u#2A7^?rdsU|Y1{__2Gj zp9IHt{p{gZ0p<1LDJZ>btd~|NAM8ei0__EboxxILLe_*!&o0iQErEEpKS+Lv4>^2hfyq?{{A4+NiY-dH35nLm=2@)3D z<*H|T$*jq<9MLu#DHm-Qxh&HNeIADwa|bzs!S-S>hY{16SL+hh8qo6I!yXb|O;3vJ z^(2>>zCtlzBqLf!bg>j;(L;L8?ur3T-p3YeLAr^81g92oc)j? z^}nq(NU4~mA*4~NfJ-5F21Gprr>bnjtovjbie4emH4&M&+O4SORT08yYl{#)4iKSQUZ zoCj{ch>orKpxo)DoaX>=t@bZ2>o|yCW&Gu0gr*{#llVk5%{vTZ2f=xtB8Mv zh;Qxs1-{12m+h|JgZZkRPwjkfrsJudZ%m?4JKwWn`hcD93LZr`co!b^E{2u?JIlic z5cstIC0;)`KdxVmD)asnfw&$EH>nFZiFuJlRy7MZ9O27rK(Z8(omd6&o8kt76j{1O zG6s1Ddin@ylKzj#@Ucq?qATKmYm_ez)4^`!#{tW#^NFLL~nKtZ8EWt z-bikj&)k_XZsNHnJRG=bT*WXR&+N@)c?vYL#dXu~wN$u(-*mp30tSEk^4x#_kqs48 zOOfKoKHIK8wD!G~c_z|RT3>972X1i~;(NoOxkI+X8J)VVQmz z2!(rnB)4Y$a=b6sUz*ZJ(%99(cy=BA`gK&Z-<4*+wkNhMoKga*)SC-e`uWxB`)0N< zwfatK^?hMX|7t~nQ6qo*vI8n7EAUw>3al5|SM-;gE36*U$i0!~#uvLp%yHLtOz>ii znV&kz708MwZcDf=$Yc$k9mIx1PlGDMy}a0B+O@EAhgZx2V_4~nmXEuW5B&EZWYTFG zk;}UR`w6`&xAwgicnZ=}T4(Ji%K?AC{iFwEd~&3bYy6SIcRqh8RLWt8IfPIVsZ2EujL20UY(@f+|Goel<4i4ZW*4kR3bqGbRV5(sQ9CRZP$PL1vu3% zvnq6BrbWajz^l}xcE?Y4OoRY}-p?;{DNtn7*ra+N{9dpzDxK0f*(q+=uMaS@kt*$~ z_dJl^;|9Lmd$_q(6C4xC2Q&b)^`FyTiDQpOA=7^i79I*TEWP44K8+^rF7B|>*dH1! zQA@WzxubVoK8Z#lG`Db7;7$tIoZIJbPHyM=B*rDXL|?~N8F_3tv~Xu&t4-WlzPGT2MtakE;d1q~ zg(kQPLkeaZa1hhoX&oK(8Lq`$`A&-pOdD!LqBQDMNzAC#VEVOpq5yRV;E) z97nu<9Gp-ygz#D@lGgXXajjSearzT-8ZauGO;W%8cD~2gr+P_KnQkJUjUZKEk>sII zI<0xz^DE1H#eKgq%NSUtEEN8eeasZAKt_Kz}lv_HS}l~%0F zJJI@T?hlpzre+Lsr}fko z&Bas0Y5xWVtrbu10aNKd5MnCoDeZs#+-~nICPePv+vjcnM*}~C?f)5s89NY{rb6!7 zW%MKAeFqas7BjR6JpRjBB^3rSw>+yPz{Fko;1)2tL?%5T694)W2nCu;5T8(D|Mm$b zX~D_2I-w+9iJb2xMh=|feU1Iw+{JSA=u*>q`A;pNLl)4}892PT=yT8*&+5e;#1FiDImBi%5G zgLZ@G4ML0~LXC}-dm>0o;yZsKEq)@97>*)leRP*az?hA*I1wz?<%5VnTwRGoqGEZw zWzX!DJW+&}^zO`{$T&J7FM&@YS&)B~9|y6CqzP~P zI5*5QAre9&6nW0+WJXCVLb?c6-+&Ak=C*B*E&(}9a;C!vQ#NY3!RnCn5oF!2!(!E5 z*t!AApxnTt(D?wFJP#3zU~zju<#KKOMh9C3+?4#5m$c{g#y`dLN5J#EskPQM_H++M z(FyY>6XsMIyCG$>|J;8cgLVe1m7X&YV!!(!{hVYY4r2NObO+G%T?Oa@b678-LMi@4 zp_bV!9lLatkDz`%iyn=i8>(psg(8ct#73}K7=U;L$m6s_D5|1Sl&+{c{D`qq6xGr- zuce|&)h4~^k^t>861j+B$9VtZ9azgf zM1_}i?#;64d6&Lv6Dl)qBr}2rxFD3l1@|pw=-0E{B|QQCoE9Xe_E7{GkDxkATvP;p zF4175Rw+F;i64KYI6?~|Zk`m%38^eplQ>T8UC8%F%S%gD8H3t#w?dLhpNC{wnpAT9TMwQ)A`4!|6ITw{k8mXTVZ3GblZAi%5c=`>{W-T2+UB_8Pf4bA zA{=Di#3bYs5Yks+VPPH0hX5Ps7a6F8jT3nMABZ(1+dJ2Xqx5#>L9;!i7e1KhbSaWx z;Dl?X7!N=(MvlxT)d2F|XHN^~`WzoHNcWg|G4pxUWDw+G{gr)REX;9vhe(+%qGXGI zyRCKMRQ7+&#Nr}i7eQ<%i0#;`(C|6(7emZ^as3)7A4$OC0VZkV5Hs(D{5X2CHnyup zh52uEOuz&L;z z{rR>~aYq0^`-Ma}sZZ%?AapQpz73%4Eys`83&?*D=G!nG8jORYzql-)^(8LYRw+M= zdw*+PrP6Kw9xeqhl>Af5()c8)8N^|+8%zeSaR6Ot4NJ zH@RT=9LTzXucY8h75Ny+v8siT+LA@Oux$hf_LwQDs1db<%1C5uG+@=XvRm0Rw*fgxTLWaW0zEnU7fM-*l<^P&_*+9yAWv+Te<$khMQke`Pz>W_KE=+%@ zNGzk|F-9I8*^)a|n$AcKu3r-Ar~bx(mYkx|-fI+4b|>eV=>EOGpl$;hlxMF8M6h zPvROAxQ%y0{|C*Q7;$}S2-W$mGU$Jh?914#9Yr*WUqh%20)oOagvvuD=IA62p%SyG z2!iM0PV5{9e-upR|8_7{6l6q{&_=;j1L-W+P=Ti8X+7rOQjb|_%GqV~1Izdn;kqNr zizySAF=lo-GsW4-0n6JVUVo^bWqO^2h`c@_LTgbDolm8t=@b_|j&{uSrqzF-U{guR z{XlE~OA9rPLT{ck#_?!e{wWhG0p2rQs=#)JPt^KeJci0|8!9zrt0a|3vz)mXPc&Q< z%E;qct27?NBzYHZmcWysKSW%YoDkD=3b%N5zFP9RgHSU{cQ<6fL8uiq-ng}wmNRz8 zo@wgYTW6C=mIHoo%`}=;uW5hvH`HuiG~-Uw>NTzYf?Tm_pl0;@ ztorxl@dGOL6}0?LCu3?!zDY~+J?akAl6+ewq%Jg-O-u4MGH@R<_7u{;)}gqK!$a#( zXdQ}|tV7X+7qW(H$$l-_|GqM?mh9J({m(0=e06@}97vY~j`}V19WsBPLCkQ5(~^jeguPy7|*52WL-CPFEa!r}prC{yX^3$=ecc^QecH@q~h7 zY8Ymhr}WAeL;h^ns6rk;qTS^K#xT+st$gN?pMU?6D_wFa;(X&8=tN|0?R%>vI6tMQ zw9dOb7XvYi(SrXDbLHk^1 zQ_fU5TDj3n2v?jjY8i@%*Ka!xfn;EA2=ve0mPzJlA`_AMr;C5AztbxbZOI6wHw+NT z`5_>Y@+c7?^CI6)Shz;2iyAZd8)63a_&&nyf#5(DgC9x^R!ko|sB!?)--A}>v?W)I z8VUbfBH`7dxz?gN5*V*~>@5hZhK>(W-A9l2CMj;Er>F0bQuCbdrUgiI5Tr7 zs@Uh{C|oqa_0fNMhKfH*e0BY&UjR$EEU2Ixi!6jewC`wcRJ8@uW+NQHkotU(h2zs7k70rDNn9cZ5~G3%?L ze`4@x&!5)z(7PU^HxFo~Fega?Uqdb=(vXYS;uBeXX3u{T%q@dxo*`~vz~Q}ZY_4CA z^e-*BpU!adkqzB2$8+P`93~&jY))r*FL0WD0v$e;!&Dbf#L+fBNgfg!@r*4W4gwlC z^$aF@xSb?riH7k#5em)N?fJ-2qU$|x3RMy0P3NoetVzF^(x{q8mAcQV7D_+zQnOB4 ziDx1`rFDPSq`w^S0ZjT&K}<9V=_Xo{1|ew>(rX4G>0vm$$a)yg*0IL}Sxna$sOx=> z16Q}%Be~5qgF-VXUMYj3hWk*lS60_GeB=ny@R2v*gBm_EhUpqUa^LWgCNSNFu_rOR5_waTUN%o-9a=`|qEpT}|ZuMe!0d-Tzxf7(S`}uT_ zU^)F^9yUs;Ica)nqANGfqZ<7AHDdX>F)6Z}blZI!GM^s#*A z7^i=G1mHHOcLe99A6hn@_DKEvk6aSnY7*R8HB#j~ZtZ)^5x;0daZhQTPxe?0_yC@v zC}qw+d%i?LwY5OfAEe`iBY&__5{{%|fdJH=1cLT|sIn19;W$3nqyR!tMUY=1&a?x> zu_krz8Rw255Mn?q<@QNlVkQF=W}5`?;U^ffrBU*wmbTpNOEh4CEV;kKfnr=wB_aDh$L`X{PxGndW)mY)CaP zK9YHH;8ahwz)WND)z?_lOu0{;t@q`ABaY>Fl%WQsgKH4n-3h_p!?v$}&@u9@e$ZzX zRMZbThUw}DJ!jhYo^0+uM;zbcGTDFfxwY>tk04e`+wk9d()dUH8Dn=2gVPby z0avQ@EUAoEc$=ZL#am& z4}E2tvfxVVGlyR?MKcX#ma9DVNb=M`O@M84Q3otg*LYj*lLVtd*Vm?w3>1ldbnZBC zmd~4T$LmhX)<~~gok_Rx310(;t19z0kdjt=WGstl@~Gxm0M_SvvA{`&3(q6gfkK7ka}kT8gklQD2jR z=<5x| zWJ6HwnA8uFm{M#O43T4>VjJv+%BTjs-hxMKy{IvTSF!F!+UG-y{R4mc>&AvgGf>q@ zar68-I<1cN>ym^`&pW2cs*UCqY&5FpO^>AK4U~;gr#Y;}is{dZ=>th8*D$DXA3yXP zh8vEgY&=CWg45D>Ytof9W#eg5Hm)I<5Pad#>itXx~UwsP$axb`)BKHsM>>7%>x27>oqzufS) z1-KBeW*-x=M63wwA5opw9 zkrG+Vu$5W3fGm_`CJ+*<`m?+9WRkNxFMM(5kztzg+Z^0^zc_yl<5#DlKXMvg;6LjZ z_az0pfm1qkkDgz~ICPUAo5N%sf zT(UK@WirUI=Tv>sQ+-IVABQ5QhW~oTAj0AxXg+^4`kqMwPEJ#oPXV9MoGgOBArL7a*jw)F%>h9U6=V^V?S2sm<~N|v zD^9K>fgmmgf?uPE0!I`(GgNUh( z<9+m}0UL)V>NFaeS-G>lCXb!uEakw<@D)24If_1x;^1vl#kmP57J z->b!j_223mzp8Om0&ZgoP{sc%#edCddR9|`<}^*3)ASaYzHLsE3-@49n$z?OCLGOa zS`(bBIZZE})8q;rg19xoRGDRvfOZ4GryzYjV*ucgBVLm@+fDM)finV9WdB=o3os{eo6g;RTQEJ)+;FPwS>5s2n4MBrUw zBQu%}9OY2i)9^HwT*ZU(ivS6%uvXZ9r6yC01NAH38o^3pP03Nzp zUI4h1*q4PnE{0&QpTRX+fhE#*2Z?}Ge8*xIw0#RY=6E5h?>}+@UNyLg%M!qzAb^if zx9)!!#AOCuAD+P*S`J@YlOM1SD%tpk@2+3QYxZpPyKsj+tA2a++rODNQ~man`t9EW z(>Ja~TJOW6)N}s|_7e5ntLI)l_c-8qdy=Vgi~8=>cmG_zdzbD*8`OFK+E}X2`)79E z+g;Oy>&~g~UVZnELQ&LrufBWr-K+2Z0ZD(;i0}RiZk&9R#p>LAh3crMmb2z9IfOH0h0l z;O-*{ZL8!DSfL(W5g0MizlU@c{Cl5Ckk-Gy28T_L6dYF8f4K!YnZ4g|tjLs4YCTfBI;*74KqHgJo4)Ehv=9PxMyIH<2 z|IQH$@%Vc$T+sG!yP(r_s6zPwF6eDZcOLL!DEEIP?myyx>Uz#6@d1!fS~wtcBMYCw97 zW0#8}{9_`#h9|3s>Nl4b^W;5gFSaY{mR7g4x}_gv)4y75=0Hf~EsL=%X(0cjG_)oe z>}b7QTV;m#fNiOOJsBbxraPwpW0E-i@1N6OG8_*Rco=5{-V5vmwln_ zgiE7!^UL97`C3UB z=gR}z`}@=+N9SDo;O%8=ZXLO`@2wDUv-FhKPkes*CqvCtb1~p4X0rT)4ZEZ#*BUMdPH=yJV&t=^`FyH*pbb+37P4VKw&BJfBRiR^$B=Y z3E3@|xg+!rj+1G#2l)ezdr8kNy=&w@c+-Et>=@#jc{y|lOxfq|xWIpQG@@QQ)X)nB zX0`cVfIOg+$S9ufB`@eec9lAX9?2;*k{9>-XDAMwII4L3PoclGxwo|DQ?B1Vq;@qkOpjz{ z7z*fm`8_sZcvrX7m2RoDZ3bs8O2(9oee>nEEeJ7C0cG2X`1OC~$gi^T?JR}$ZX6r> z*mC?pv76Utodbxk3N7u=0qjw`)7fQ=Bb)FU5)x9?ibBsRgOv4OPEDXhm-6cMQjP(e z@%jaObkWH=rnzbYz2K=ISf5&3l3KI3Jzf`t{Wg zmDiFXc;s}lS(tx&#oAau3R&UOY`MdoweY zCYO!zO-(L)R!rCAGEFYiouSEPlO~rvW^&mr>(?%A3Y(_4xfJf8n7G77QS!=hQ9n=> zE&#`RaTX6`p=Ia!l&fq1R;(FIR^q4{h z1q+hq*^fX+!(yYB+$lGeWkUhDhM#m|>_T-*X##%X|DY7hRR16XW_KoRhkL=S%}=pk0?l4E|o9e+uYxRRjn+al#9 z#8(HXQe8iZD~M9qc?x6MZA_KkMHWy|;3g%cU#&F%NO{OjPgEW_BR~=K8^-Wz!Gm>u z2-+1)CepcB+cO!B2Y9G>fNj$hf?XZHvhhS}+HmWXdXJ6s;7F(W5=&yD`4U^@OFa5M z2}p;4B@bMz z>)&5v7_W$7w08XhU%`7D^6%0ec(3L$Xdc6x8L%{uVN9UVJceh*^npBvYgkmd4~u`& z*s(7w(xZJoiN!(xA}oh!(`M1`%6M@%F`IU@UVA!)v++hgkrUPk>N8WCnff#=```*a z;b1mi8DHer7u$XVS8ZIs8d}(?k*lyJxgw&FDG+H}Vztnva0)n~3)dX-Uv#O86?98o zDnJdXtXLXWPO_L&_}8Dn++Q>(`?r5Js5Bi8#obDS8mb`u3_*0>YIXk0pFOT$B_)bu zXQ`{F)BpZC{dMZ=dw8f$i8+fu>|Fb9A#E)-IjnzUruTJT zBoInk#MVYi9SIer+lx)vbj5)B7~dTXGZgJgZw0#*8$LSN2uU96b0PYKQ62IRouIYo z`(gqhbEwz=C^=CWk5E!;?oOczUjt2zlJsQk0Zi-Bs z)>t5S!S*!ZIc%i%N*k#XgsV->cx?+lP7>nUAe@E^;QMV?9fEMg^A&rLkU0(#0vh#b zx6*fRWqCkAjv&e`3W`(XXAjkpNzS1<;Y+AaWBQiy+Z;l5ehCPQUju)F{82#A%`DU} z89JDCkKW{D^MPf26Jgt|x58`a6?03)pOQ>p%Shu;TI-V6NYj%UnS8(1#w%auIfg7tfDhgoOD+NEpCq!~~M9tjr=L zEOJO#WK-z1Az{!j=}W=3UxcFa-pGM*ma9cpa1IgPKx%WlC+@G+oX6co#DE zk}iP}V(=c)*hr0XmB!AiDg(>-9*C9KCk8YF){_6M25Nut6B0(<5Lsp`66J{tTci8Z3Ztl_p2>8|At}j^n2R zZ0wK4uQOGkEcd}LSAnt^C|9AP{G=NeVA9z41w9xEpCypuUL8MnF9!ex$EJtuVfkUJ zu^2N-?;7i+)yZLAr^s>IBGQAS8=*jSz!18TyK%l3pj3Y?63Yrt_hR($rgivJlYqA0 z{pz|M^me_krE;JSlVC%#-nu$)(Dkax8Q%J>lQSgQtB>jOD|Pu8Kj?j>baVl ze)p;8_8yc$m3>wA-%JHkWq*usshR;zmC_a1-0BkEqL^xrGX;@Uq6Q3tzQilXvzFBfIaVPcaEFZx26gc+mkVi^A_6M zf69L*ZXlIp2qafP?xMm&mf2GKQppKt23`?oZvTfdAx;Gj8@O&zt%A!;1o@SN?&)KO z!~_IYC>$X$iAoCy=i>pAstz*AON?cJKLbSz905hDVxXE+!z;)IC3iuQYDl131BFr;gi|VQ{PsS#t>73z#c|R=}UXzG~w*mYn*@?^t#| zJa6jPVmNcB!<}K5`OZWqTO$!eM>VH~;BWBg%e(!U=GWYdXWcryj=Tr~1_$A6SES{VA7pxAmXu(XEtmq{9Ep^Z2}eHLjrLHSNkhq;B=& zJ(3?!i`i%~o0lqPO&cVLrGdlIRZKZS;ZHa{T{PnQYrLKtdv2uYdjp5apxLm*!68^XNS?zV(nxj} z=KhKM(?|e+EF1ESVoZ0f0{qso>Z0xbO(P9)uDbTb+}*3aan8Y7OxS;=?qKZ`z?EFj zI6B2|T1@Kh)nfWewMMRW=MV1HT*K12N{^UbtHt=<)u3xSJy#D*YGoOxXo# z?t3%Zykn+^&b@iwwYnVi0bHx99lbi)QSC^zqgU6Cg1MJ_^P#;k>-|Y;6ur_YI^bTt z#!X-Eg2$@XK9pLkt{s1M?Yxp}r-u7bu{X(9T%Qb~IZxBjIk3tHABqnSq?0P9PeUhp zU*mCdqUdDXtO*1j}A71j88ipG8Mx#X!Z(@%fx83gVboE;;nWXj26 z|4C{%D1H@y-QU6u_+g|!`)4px6o1R1Al8vZ*D;Z&VrtUMh9`8?_3QKKpSr#B>TFHjxG`saaR%dk`UmF0U*%QyIL~1p7tp@+X zn0~_6?>&Dd3DkgkaNMxOCeNG0y|;@yT$RTD(BO1IwDnU_z(D2XE713Lk{C&T#M zK7Vs^T+xl5Td6%iIP})fqxRRnE?}hK`=iscO?SJDyF=u>j(Osd>&1DGxZKA!{ziq`4SR zpNoHylICK(i|U}c7@CXmnzK6%VbSNA1tAef{hkI`oXEj|sA6dpHprc za{3Tf6*(u!g>-1|=XMjh*z+U(d;7er=4jyG@2gQgL|MA(A*zSGEv66XA#Xw}2f~uC zad-K9aJ6@gF&`wW{_3QStmLhUGOM^QVU2`lq5r*&mD|`tTEA*|=B@_uCMffzuHN+%@ z;siJWQsLL5v3I1NJ+m-xceJI!>!j+qY94j+=gmj|@yesOEAsxO^oaMEd6dlWu2erR zl@f^k162C)6%A2D1wHTM5y~e`5*}Ec-*1-=n{M@2=+R#f=CXwB+AgTe8Z#A-x34ye z=6_rD*)24`xe9XY*+05c+HaQr$u;|L6@FaWe$!9o@APnET~r|n@OAf7Lp|mvXN{ziYmJP4EvxBV&RD|; zQ{G+GEAI257GWT7@hsmWv{tZoH#hH95`WSD1fu;7LK_=%eg(Pt&#qO({kOiY(PGhd zx(a2|#(E&EFZ>5G3}cVR;z8`$jDh$>EpcH7&vs9dCmxDI7Gdv=n11}5VL5&g`6tIZx(=&~Hg$CN%lP>dW?|*}H zB^XOuWjB9yTSLLbjs?BTl!O(56Qfa^?Q9DvTV=Aq8yJMsaIq8Bfh|raOB}ux2v46&|6VbD#LHbE}c|%*PVm9-WPDY3ByD;|%;#*n6 zBW7D!ZSTzAln^9(iP=YsBB-PbBygkfHkUuQDNQpSS3EhEr)Pi;=3W?`8w|>nzzV=# z|MDrT5F`Z0TQ?_~SWH5(kc>&sy+(}S4K{8FE*|bUDKEkeg-)1lK8H#}F@O7)3%{oS zf*;%;y2&YP;_GN(^rW1bA~ffOJOFd9zd@xjGcCSI0Ic-y?hdV2CQ1N8F7RA?@%phB z)ka+)1V7Kx%2$b{wTdK^c8_JSb>~U@|C(7}6n3RfNtge(`~Hj4^O$6FbXTH-9=ngPu(Qg)R%x@-x}@RNWc*~pc5~SG?60>=d!ziz z!?!2+O+LE+p~STIy!9S&DBls27v0{z2{vFF$Dp???W1Y36*B$LVpoOEFdAsfMAjD z4bmT}Bo>kES`rF}$RV@CpqPiTM028C*JgqD;i7IXo4vBmg!|O)N^2mnD6738K^cyd z1oe@pbzr|kSaC>)5<*Kz54VOx6mfWDE8}tOSul~$fR|lelI6i0ZAtY+6s>u{gGc#m zb1r66#@FH<$DHI->3@grZ3{Zf>fCShu;X3>ROzMJG*TSS!QPNF){9_06cnIALnE{+ z-!G`FV~iEpJDXICvFwc{LP8@F6gYi#?j)O@H4U_rob;sfybO~cPcAajo(?|vHu+Tj z-d@D#@+Sg#jOAxkV5=fWV4Tz>@s9CA)uxESBWow)@n(i+LVt?G*+&^?NFS8p!Wqj? zM9-QA9Mev*zQXM1WosR5M8NzM(Tc6|VlSZm99nBxg6k%qs^8n2xvZ=ez=I+pY&?R7 zQEXn-v1eF1)drShmK>Ckn5BQRDXAhuU^YU52Oc#}MEn{Z{05dSZ9h-W*m+DSpFbt9 zJwUPFA~|FqY=0(!83>w6Ebm`6t`zG|-?k|!Be4n=#q~1_Hm-L}|NiD|mIiih7PQ^C zGG?0PJQx>y?<03yy}%v~xk|_56*$o|u^Bbl&Nk^|XeR)1EIwEgGC0K}@)_`g7Q%z# zi;idFU_s)Nk)=iKe62W-9X2+OvirWUYw9`drt;TXz<&;ESgge|QbmTqsD%QDagHSe zPm6GrIg<2kH)c zW10}^L0&9x8g3<;DB|$QTE?Se>pEmmKU#Ak24=WNh)H=XaF1h80f>ACyr_ln4m|}R z>N)KEq<@@*9poH;>NqklIGP{^4wq63f;f2x!{uBPMT|TQZ$drJw13{sTgkZIt57kv zK8VFQ_MWT?5_?~Nb!3a(4f+G3h{0n%7}!htgM*LDO+E)+5W+k3xJ=Y@*yXI8gxzT4 zG7-eU5v>r%aN{yj#NaVc&X)sXoi@s%JnrMN+<&Es5vUFJ4z+fwZvwDP*l%xj89G}H zIr@B5AqeyhvwqB5E^6{Q@aEM73A|BKpXllcn?^8&r54b*r;=O=?S0Xi;bhWXr13XYnQja4>%}a8HKi| zWPj@1R+@S$o{`(=qO#|61LyDG*jqS6K2;B;APV4hf4A#Is<;-2p9*7rjq+oe=fPhtQc#Oly01lAd2 zt+(gtCy>Z~NijX~Rex#@!SN@Te4WX%{C{biht>4| zr0dUz$TRGCc>@%sVJ3eAy%RGas-8w2ZU1?F6$;N$u`QW?H*8^(_I9{meHx2iG&P-= zMQ^lq395(%BnyGu9pWa!;XS4b=zv>4!&gl!Q99pgYCM>A>^IL4S z?N#ZBb0X?fCmoo{#&c?wlGp?tmZJTx-&dt>I$@;uWY&svo6a~Mek#Rn`d6nWvg7@P z@J*o=ku2w{ZXb(z|IxNIr+ZU!QvPun#}keV4rSH9betu*LR4b*6sw(5jpvlvaxVOy zsJ#92)T-}^#!_2vzKc9wW4HRqv%{$&!JaxwJO3DPcHD_?*spWv?+vdklfJXLUrIHS zZ~nQkenr4fnJT~O$Gu-9zTKm2x5ijHRdLO+;w3y5z*f zODd6bwI-flxV(P(tmw*3!N(^1Y@D3A@qzH^<*N^dO?DA|d;iM$ucf+T6aQsi+tR1g z8K7=0f}=#P#Z7Lr zn15ci;cweJ!(|&R);t&9u(#!Fg>ZeDQm5;YY{`ku{wF%>#P+Rhx#HQ7zvFh#$|a_P z6%sSwZ;cRZZaSy+`$cc9^*+}x!9RDiv)$$UoA~f`eWdzYW$#70bEhA1KK8o56Igc% z9qH_l`Sfb5*`92{J#SJ!ufhJ>+_m7`)kkMjWV+8ME}R%qvtj98;m|E?Oy#QA*r)o`Snku9?!Hv>NY93sGj*!F zcl0qV`1O5%aL}Sx8V|~wcl2GEsC-d0+O4y@NBp`VFp1cm?2xJYqxvfH!>K7DEcsh@ z^l<=P&>#MJ-8|Lw9=)|@H%~tMUw-`2QZMr`?GTmS-+w>z_H$jsZarm&R+8YxrNJg~ zPAOZad5XjeX!?G(XEk1aa&wBpM8?T~mE4sK6$})Dxb)qO6by}^Ok)K@V<^)^!O&!K zn(~Cnek!tzhLi18U152F8X)#-^HF`o8%oE{P?n3K}j}Mh1rF21s(izCvnVN`6unm!a9@Uux#2hUQ!b zaG+pjYHDn%kfs0;Gc-3bwp0MiD&)b%ER2jMr>UC*ParWdGR2TJu{6UFGc^Nx90ZU| zF*CwcXJ(11&fFA3orQrV&{avO23i;y0D}}w%-GNXLkxIs3Wk`eF{UNvrpA-cX-Fpl z14ut8Kfgr55U2(ed!Bh|`3iGpA0>w9@_x$@eA^cilVr>xtJT zzydbmI;xIf$0aT1T9DXmEI3{N+}^GBc`}TvZ=+z1$}>P3Zv-Q2^wv z(GHW6|LxPsxuU zqQwUsC?ewFfOK;a!_(w?O2d%fDSqQx;SuRiOBq~&5jbKI_%g1-yF=1!=SgdO3`1Bf z_r&^PnQ3&-rc29OU}bgJIHxFgbsqdCh8U5(6J7XM0~@zfo)va`Kfw(!+JYO2FT+(` z0Vl2}ztVp5`~Fx5AEUiY+wJYh4OJ4Z4n8<}Pk8Tp*hx!3s%z@gUeAM7Y|5q07V56v z8@A|y@7Ld9D&ZXK^M^9@0$1R>mr*A5i82({+R%QGJYK!oI~418YDMIYwcdev=1-1m z!Bjj6@A1y(pbFd8Owcg{PuS+!?in9dd^&4Kv>X!i1GWYDl4IrVas(Rq0xd>l6a8Xa ztaHwXzqr?*{t)u)cd%JKo=p)=o}IOH@osn|k|}Ad6z8;PvMX*~SH3Ae-F;YXTb~&G z^czvzTD5aS;bHq(XTX3qD&J>p%*|*+_c2k`se>$!a?U2Wu~Wz$ux@4`EFoV_XF4r1 zoJ{KEhm0%lHH^fICXVV1=*S`;S5$MeuBu{1!=$LE93j&(sIV3*qPtTBJFX%9^P;p=jjyJvSU-=uQ+@$*bT zZiMmbJ888YKlVvNfN#mI$I{@QQo$r7Og<`Gf2z)9Vd4WRV~A?vuw;zlC3^pr^IgbA zBPSJI@haP!L8B1_`!uW~d7J$MFOH3zCJ$x1w$I{}1VrfjP?BUVTb9rP9ip%cmjne+ zgG@K(SvAo9oFkOXF!(%5q6-C8O2P;odUf0nF{-CX;*oX903uuQ_kQilLN;apIrMGc zw!UYg)vG%f6`Av_?Of+@h8>Jk{IghX7h63~8!!4M`dRq+O1=fFu~w(B$@y*PqA>ap zWCLRxQd+YYg?4lP5&f1v2Nz#X=xWB}mC^X%wG*?=+Ue2mtPc8Fx@r{^`4qQdLo-WZ zlJ`oVPdd830lLPOL2i|Sq&P097eyxLfyvq*@t~Fw3UVe>nQI1h7MKE<=C#apsRd~* z@ISwie%q6InAbLLh@Tcgsv4I|OPx?zhJ&|;FC$ypg=z-Ze*wl%Ky4Yujw<+KrI7 z_Hs9#aarBxqELGf+VY--NOLOj3c|YS1xW99J6slg0#elmP|PCg$oxU*qdb(*an~eO zAiO(rkS2me`^im-sJKz9MT`&vOGq-{fF;Ms+sOp0xHn)iEmQ0yzBnJ4 zo1YwzkCcV4o>V5@SE6uY?pEfj3S(AY#X>uZC{3LP&O`*m8sMFXJK)8-L-k_(9olDM;Htn7Oinl*Yx4|v^__7du^2t;5KlVAXgR*9yA-+`RGZe?McS&sRW)d z*mP@LXAxG89Fk`vaU3wkF;$5(2(Ym;pgY95N&1FuB6v;hb0EQA(k}GfS^{KbM^qED z!^H_K=b{wp;=jq=sMRCo0G%-F04*d8KQGc5G()2>Hpr+A6D?`TCAR%!c$IqDFIJ#X)%&<};?$9GJ%sR!Spv%uCGv@P`eTBU~_W4c8j&bpFQTUFL=p`~_;P@pADzum~tXnJi=<$Un$DN-j4RTMPMeSYURt%_FT}IR+I$s0sz2sT#Zzh zt3vE+VWRq3*GFH?0=m-hX6+YY7|0D#DA8xae8pv~NVwgoi;QdKcq|o@bqA4tP;5qg z$(AW{UR|cz_`a>(>3nR2MS4d#H`Z8zO7o+}Gzqjat~LCRw=-KJR40B2S16e&B+GhU zv?0k;C^h_*f!MkDD$=dWfS*`TF8`r_&+T1?8!+hWpz?6k8?ZJjohtc_K%zKR56xJ} z979pnYiyoIb$*7_)q+))ziFWz>ngRvEH&kT>Uz2Xy@%>vqVHK0T@f+axzN%j`Gc%# za-!j38h1lc^CCBF60g>l=G2!+NnM@ZyfxeAJfrPX~VANMAy6(higa1%{ zA}|15;$jWH2TSgy7l)FBJ=}hjr1nsaA~Ef~En*BLik1Mj*J9LZ5XsFyTHb1AJ}D|u zspWzR%LM^)-*T{CdriecCuv>Az{S!Lb&6N5GiG&(Cm_(R7HPV{t63)^*F3aEFti`F z0IlbuFqV+U)_!OMbWjsjs@~xGi7ylX`BfH+8s5FF$9u?#EEIeN({=bWg|-h}0PHLkIRjL*mp*lW>&qh}j%VoINeen9$4U@u4j(oI8PX{xjZk zIF!uxkmE#v5+6LcJSGIBh4;Ww7bHAfq(6?*8?2roT2v4Wpui=bLVsBv)%7UphR%&6 zGD;d3?aOWA`CWKjEmOx>KRm(DFj#Ko?Hz2&dFOIALrOP2bv%4Je~G7Q%~sSg*g7Y; z0?Emv1fULW)LheHPQHQ;!6z@*k1wwx>curfl~RDL=brivv3a~OTL=<;t>a95VKT;) z3LfJwNe!@v^YuCPJkA7v)Gd^SwMh6P7i%K9DfO;ms1g>(|BiNZA|@C0y5Mu}&@}fT zc;;bpE+h8>jy~H8dr`hh|8UEf7V3n?H5Uxqo3JQ8)6_XW*H{1yLf;jP#D2}UK*lZ+WTZ4Jo}8K- zO#VMpDE5muKDiIZ>;HXoOQr6?00t1ni^WicZM{i(y29tm-ClNU}#l%RU7T ztf>L^!kS#YG{)upd2Tv4j$%QKMFHnQ=QqGoBpUlVekOrp3ad3DsYKbnJZWnct(1d= zdScUjrI1|ZR=@;=kgECVvg$0J9#a~MJkmwwJq>XXh2)k{*cAG~6pS`B0-U-b)Ck9* zLF-AXgK-fQhA9TdScaCURjx0jKJfRcDi^$7Q4_9YC|w*LH!0&~i@35qd;kZYr6Mp= z;&m>tk!!Z=;^G0CzS$mhF=!~x%W+;SdbyQzrBkOf66d{<8U%<}@mZUrZu0Q8Z?W?x zW!7G%w9cAKR=Jb#(28QtXSPRbWU^UHS8emQ;Sd8epA&$#-yz(+E7FF5g>vhfd50VbY)J#Rj$2~};5z@FSwH>y0W0c?p7ha%MR7nLEF**uV z#hHDm^bl6Y*nbMV`WgnwvyuXZ!?$ANA>!kGk&a+m0gE2;q@zq_Rf0J*sPa;LKthE8fm z)5SU2Nj1Kq30+5%h747`F0YC0LN={NIK{MH%iy{m<3J-aCOvnUUkT2gEPVb;y$)qv z{#FW@bMwB`Lh~8kv%W=w-_t%`P5=DmhICJL`C#X+_-0|D{>D1m?j!|qAitdx9LPYC zj^L&(_b$9e%4%2a8MvH!=-NkohP((vj)5k-h?;=D0(2S^@x-8N58>mhk*-Wy=ZCncE3ubEV5$sUXrigWPg(Yf#Kv0)xC$^;@LP5;NjPqr zfbV%#;6>m7N%#gj`$lU;Z;g|%fl>DysV^7UiA3XD*z7dZ3|ltq^+YV?GM_Luw-b$yP&{yn0PsLo>1xK+V=F8S!5&v&C{MPJMC$iP!WoL43qiP3SP)+{25 zqDR~4izfi@@3VeEC8q4({}X&dcusW|7_4f2ek6AfZ1XPE?g^;k-){9@5JWt3Ehsnn z+L%4`s*5!%vC!#jNpRf#B3=1mPeVdpGJM*!jATUy9lfFSL;)R*=spp6l!G!?9kHf{ zkooP~slK?#-69+*du%ZCMQbzpCHdmIB(>*RZoEIiVf;az1lvTEdIkiU0Y9JK-vNG$ zee9G4;4S=WX@E46JS(4_snGRM)9I&%HO_-@%<;iNmF2s(QsRjHYq=>olNNok9HwN* z!lh=5V3Ee4iP#}>r|(O&w=l5qE8VG8FVb#aYl-*+!M*v(d?79dl)>9-Tjui3lnh&5 zY%_DOL=CBXt$D(95}1m7%#O70t)V4LSZerwfS!sFf`JIrS1VS()*A2pO5gB|3q}{`QnE0y3HP&bQ;w_a~5phZ6{)GQP9;uwPWb;X#`n zP=tw_b`vcH!mOAD`E?~-lMg#VW~QJD+(2_?y zfR8Of*MMG*=2n#|}y&9F^ReERY;3ttG#f^&Vo_5BwDU??WWPmX0P z&@sX{>#DG6jY?AI4A)wa=&*Q(yz>^|Kg38aU9ZjQ&7w{byWn?UT)f>{^oofIB!54s z<MJfq0r1{f#mPuqQfvSSMg6!OP9oxC6$A)04gx{gD@9M{y zKRM}VqE;>2WrxWWQq+?2v57Hppj}HvR>(>X`3HRPXhdeO1OiVoMw zd&WT(u&pX?yw}bWYFS6h?m^Ae`0kAnu+9z%P3T(OalI?xSqieCFGa~l*L(q^)|Xd} z)Q|BpMf~iwu!t90-YB^yd~faxhF0enYgFlx$_y>sv$VI?pyvxe8_>(${nXljZF_@l zfl}5@t$bG_{92WI@$Ty4eB6;5Opk5v@x<)}z{a07j;C((YXw&RG^RNgNVm8uB<8uD zYPbF-jl1$;GC=J7a7|Bm=Vzx$lk_fAmN_GDG+L9d`sXG>5x}g}Rdgbc*vT2h;|V{7 z61F>Uzt%&TF1wyITGY#u%FlzYR&|Ec$cqN%2Y25a2Y3-CnZIyhoWZ6$L!F9-cHM{r zDC02{^g1hN=hFTg=kpa`p%NiE3=sN_Dwm@oBNF!=#cxetrzng_AX!Ev=pK?6Dm}Vy zY3JJHN@(J(rMcEpvfAt4hb*BJlz#G&(X+$ze2i?!Kl!d5(meE@s#dCFOh@4qZ`00U z>Z}26%u86ITf#4Y>`0VMPSq(`BK*4tz({GZhBSF@wBSf3Hq_`NBWIrjUM*90VLBkJ zVPOkWosDn~el3O(Qhm_cc*UIUnKsK|!T1?rj zY!H{%yE05{y%zC->%`p;cCdp$$+9(9~?_VXs7v-8Bxe32*)Cb2-ykaAx>!4zHLF8pktf zPb4epv?r22^NWtXwgl0eR6qH3Ci@`nR8B8){f6ZAOJPzzB~^X8tG?+QASpI|^yIUE zii!b2igaaadIgED>X?^e!g68IVKY1CQuq7-w`$EBx((qEj6%?OFz>&%9BU7zl;i6! zz{a;?RkwQ9z~`%Ddg=WLEk}GNHRUgi{CF69HD)ySB z)~1&IPCS|6Rn=U1?>W9Fw4-!0;Hz3F9GofUzEoej5I&5o_szSn>is>;gt>Lla&#nf z>AO0wqc7~b1=q2RmMwHZA|yE~@PHC(YV4Wt7J+=ReEIq|Ghbt$0Vo`AVe+=zyCxv| zj<5#9^$CWK5L9INM7?6LN8`^vB>_MmbXFqSJB34PI1Ceb45#$9vn3#2y6Rb{5g-Ba z8+JWg&bs!ZLU}D{h1igQ{@R0FsdVFtPoZ;HCSJRV(lV}*Y$7FbUCyp)i~;rt?r>y6 zZ0M>I$opJB`uCIrfwy!%y3r4@O0JYt0R`Hs^)?VY8J5$gX`4^O49r_8SC8`OM$BE# z+?jbvpJuyCQVQ4^QG=oA6!0RSC9m2T*OQ@AOE8k6BK3UwNJS4aNbG_mlBI0gljh~9 zH^0RpP(nE5r2xZ<kn04xXEnuX#!dT;h?{XBd}VRBGb3=sXdJ}}g^dnRB+I&6PbUQRVqKxO%!v+L?s7n;4#U7#8BmMUC0m z6CuC++1WTV-LX!1Dqz~edzZSVtsuywlHz_t#9%Svq`9O zWzKe^zOU_a;vS&a$M>yWJR>#jK!J!+I((uOUI2Wu!ra3N+n(CUsyt${MZDX^+B>^e z%1_R#{dEm1#(V%hUHeF%bCq(^{0Nj*!@<7vlJ=0HjM|AttKW`T7-;J({jo-QmFIG} z+GMjeTFR1-eKu~1+5qyv>`>+~O(cQ`hq_d@j~ zW57@7b=n+Q4hwUAXkpd?AV_;dQ@hP$GtDvvyBf2CK@V-Q^NE1Q7^0Q**7~L?(?rT{ zmk~|vD4LMegyyX=A6F=5+Y;6TnrDw*AszAsp&55bE9G|*lkE?i39x+7wi_L%fU>E6 zlr4lpVMA=R+|}8ZwZi)gI=1x9rddAbC_psDaAi912W&@&^~BA<5|J;MZZ7PiDc=hl zl{j@~m+fz}khRw|*1O^LmUCoQCc)O8O;??t>_q*Rs%QLEAYsTwZf3|E7{1gGYcojrBte3+O%_WfpObr# zgj@_byT3!jt&lM5*iw|C7sDmYl>k%86gB-7tFZ)RDW=@_s3F%NC$2aeFegNT%hYLfN&I51eV6XaG{sPj zzK$wHUMy1VSd|p~dRJjK%IW`0zcuOE9e)*B+s&09U98Mi^{`Q~d)GnbD6 zy%cDxh9%fgnlIbQM6GhsF#Z`&U=_THK=4=pmCM!vlJGj+t547-ut^$L_05vXp?O#P zN4VFA@V`O^px0L}{R8*(FeqD*m$fPm^8( zN%e{=DYkvJ9UI9yLY1r5SJWc;IT9S?n0d6<-P-?xxsH6X?+e}tV5TMgNEVcOfZxYPat`VnqVoz55vj*R~Lqp=k*j$%?kp9)KNHO zxj>wJ|5CX@oc#Y%c|e>335c?>8XRvmz(!!UzYkAd5GUt<6aFvC2jb-VC&~}vEj0hDq)aG&s{$?Xs?j8n$f-aJCfLXoadUCL z?%AANU@#L3$2&(eX=68Y5To=PE-)uQ`2W~mH+6FdGe;8}6fSUrlsrES7iWU6JP9#a zfSVHx0{_)O4j`1j6|jIHFMmR{JU{UI_Wl1@x%pl*@gE*M+^@s@PfYNiJYK$k^7y#^ z$>S4zO%U)O7v$#^{6`Q0uGh)>51xSF>rDJRCdke8kHCUF|MV5)<$ewPFJIta`4Hse z;rU4;n1-5HV1KWqHw4?I=X?lUNipJ`jU6B za0GF_j_L1?G)NyL4C3N9wJ^3Y1%pIUK%Ahz+P`D3fC0+ik7#2TH%}LH3lvT;n2QgE Lj!s5J7UjPHR6ua% From f9fc9c59e606214f86b39f60a862a0395a3a67a8 Mon Sep 17 00:00:00 2001 From: Jake Harding Date: Wed, 29 Mar 2017 22:27:42 -0500 Subject: [PATCH 99/99] Milestone2 doc. --- docs/Milestone2.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/Milestone2.md diff --git a/docs/Milestone2.md b/docs/Milestone2.md new file mode 100644 index 0000000..019a590 --- /dev/null +++ b/docs/Milestone2.md @@ -0,0 +1,52 @@ +# Milestone 2 + +## System Description + +The system is a web based user interface and retrieves data about a GitHub repository using a URL specified by the user. The source code for the system is hosted on GitHub at: https://github.com/jakeharding/repo-health. + +The intent is to provide the user with usable information about a GitHub repository so the user can make an informed decision about the health and sustainability of the repository and the community supporting it. + +The system has many parts. The backend provides a connection to the database, serialization of the data, and serving the data to the client in JSON format. The web client uses the JSON data to render the visualization of the data. Both parts are included in the source code repository for convenience, but the system is built so the separation of the frontend and backend can be easily achieved. + +The current state of the system is in a proof of concept and is not ready for a production environment. The proof of concept supplies basic statistics about a repository and leaves out complex data manipulation. + +Rendering of charts has been left out in this milestone but the data is still present in the user interface as a list of numbers. + +## Development Environment +Our development operating system is a Linux/Unix (Mac) environment and our database management system is MySQL. + +Our server is running on Python 3.5+ and is using the Django web framework and dev server. Python’s `virtualenv` is used to keep every developers python environment the same. + +Our front end is using the node package manager (npm) to manage and keep our dependencies in sync. + +Docker is used to create an instance of the system as fast as possible. + +## Data Flow Diagram +Our Data Flow Diagram can be found [here](https://github.com/jakeharding/repo-health/blob/master/docs/Data%20Flow%20Diagram.pdf). + +## Database Schema +We are using ghtorrent's schema. It can be found [here](http://ghtorrent.org/files/schema.pdf). + +## Copyright and License +Licenses used for this project cover two areas: documentation and software. The software is covered under the MIT license and the documentation is covered under CC BY. + +Each file has the following documentation: + +``` +fileName.ext - (C) Copyright - 2017 +This software is copyrighted to contributors listed in CONTRIBUTIONS.md. + +SPDX-License-Identifier: MIT + +Author(s) of this file: + Your name or github username + +Brief description of the file. +``` + +## Contributions +##### Jake: +Jake is responsible for implementation of connecting to the database, the web server for the REST API, and all related documentation. + +##### Benji: +Benji is responsible for the frontend implementation. This includes UI/UX Design and the display of information from the server on the UI. All documentation for the frontend will be written by Benji.