Merge "barometer: update nightly build"
authorAric Gardner <agardner@linuxfoundation.org>
Mon, 11 Sep 2017 20:10:06 +0000 (20:10 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Mon, 11 Sep 2017 20:10:06 +0000 (20:10 +0000)
476 files changed:
.yamllint [new file with mode: 0644]
INFO
jjb-sandbox/releng/releng-sandbox-jobs.yml
jjb/3rd_party_ci/odl-netvirt.yml
jjb/apex/apex-build.sh
jjb/apex/apex-deploy.sh
jjb/apex/apex-download-artifact.sh
jjb/apex/apex-project-jobs.yml [new file with mode: 0644]
jjb/apex/apex-unit-test.sh
jjb/apex/apex-upload-artifact.sh
jjb/apex/apex-workspace-cleanup.sh [deleted file]
jjb/apex/apex.yml
jjb/apex/apex.yml.j2
jjb/apex/scenarios.yaml.hidden
jjb/apex/update-build-result.groovy [new file with mode: 0644]
jjb/armband/armband-ci-jobs.yml
jjb/armband/armband-deploy.sh [deleted file]
jjb/armband/armband-download-artifact.sh [deleted file]
jjb/armband/armband-project-jobs.yml [deleted file]
jjb/armband/armband-verify-jobs.yml
jjb/armband/armband-workspace-cleanup.sh [deleted file]
jjb/armband/build.sh [deleted file]
jjb/armband/upload-artifacts.sh [deleted file]
jjb/auto/auto.yml [new file with mode: 0644]
jjb/barometer/barometer.yml
jjb/bottlenecks/bottlenecks-ci-jobs.yml
jjb/bottlenecks/bottlenecks-cleanup.sh
jjb/bottlenecks/bottlenecks-project-jobs.yml
jjb/bottlenecks/bottlenecks-run-suite.sh
jjb/calipso/calipso.yml [new file with mode: 0644]
jjb/ci_gate_security/anteater-report-to-gerrit.sh
jjb/ci_gate_security/anteater-security-audit-weekly.sh
jjb/ci_gate_security/anteater-security-audit.sh
jjb/ci_gate_security/opnfv-ci-gate-security.yml
jjb/compass4nfv/compass-ci-jobs.yml
jjb/compass4nfv/compass-deploy.sh
jjb/compass4nfv/compass-dovetail-jobs.yml
jjb/compass4nfv/compass-project-jobs.yml
jjb/compass4nfv/compass-verify-jobs.yml
jjb/compass4nfv/compass-workspace-cleanup.sh [deleted file]
jjb/container4nfv/container4nfv-project.yml [moved from jjb/openretriever/openretriever-project.yml with 94% similarity]
jjb/cperf/cperf-ci-jobs.yml
jjb/daisy4nfv/daisy-daily-jobs.yml
jjb/daisy4nfv/daisy-deploy.sh
jjb/daisy4nfv/daisy-project-jobs.yml
jjb/daisy4nfv/daisy4nfv-merge-jobs.yml
jjb/daisy4nfv/daisy4nfv-verify-jobs.yml
jjb/daisy4nfv/daisy4nfv-workspace-cleanup.sh [deleted file]
jjb/doctor/doctor.yml
jjb/dovetail/dovetail-ci-jobs.yml
jjb/dovetail/dovetail-cleanup.sh
jjb/dovetail/dovetail-run.sh
jjb/dovetail/dovetail-weekly-jobs.yml
jjb/dpacc/dpacc.yml
jjb/fuel/fuel-build.sh [deleted file]
jjb/fuel/fuel-daily-jobs.yml
jjb/fuel/fuel-deploy.sh
jjb/fuel/fuel-download-artifact.sh
jjb/fuel/fuel-project-jobs.yml
jjb/fuel/fuel-upload-artifact.sh [deleted file]
jjb/fuel/fuel-verify-jobs.yml
jjb/fuel/fuel-weekly-jobs.yml
jjb/fuel/fuel-workspace-cleanup.sh [deleted file]
jjb/functest/functest-alpine.sh [new file with mode: 0755]
jjb/functest/functest-daily-jobs.yml
jjb/functest/functest-loop.sh
jjb/functest/functest-project-jobs.yml
jjb/functest/functest-suite.sh
jjb/functest/set-functest-env.sh
jjb/global/installer-params.yml
jjb/global/releng-defaults.yml
jjb/global/releng-macros.yml
jjb/global/slave-params.yml
jjb/joid/joid-daily-jobs.yml
jjb/joid/joid-deploy.sh
jjb/joid/joid-verify-jobs.yml
jjb/kvmfornfv/kvmfornfv.yml
jjb/multisite/fuel-deploy-for-multisite.sh [deleted file]
jjb/multisite/multisite-daily-jobs.yml [deleted file]
jjb/nfvbench/nfvbench.yml [new file with mode: 0644]
jjb/opera/opera-daily-jobs.yml
jjb/opera/opera-project-jobs.yml
jjb/opera/opera-verify-jobs.yml
jjb/opnfvdocs/docs-rtd.yaml
jjb/opnfvdocs/opnfvdocs.yml
jjb/opnfvdocs/project.cfg
jjb/orchestra/orchestra-daily-jobs.yml [new file with mode: 0644]
jjb/orchestra/orchestra-project-jobs.yml [new file with mode: 0644]
jjb/ovn4nfv/ovn4nfv-daily-jobs.yml [new file with mode: 0644]
jjb/ovn4nfv/ovn4nfv-project-jobs.yml [new file with mode: 0644]
jjb/ovsnfv/ovsnfv.yml
jjb/qtip/helpers/cleanup-deploy.sh [deleted file]
jjb/qtip/helpers/validate-deploy.sh [deleted file]
jjb/qtip/helpers/validate-setup.sh [deleted file]
jjb/qtip/qtip-experimental-jobs.yml [new file with mode: 0644]
jjb/qtip/qtip-validate-jobs.yml
jjb/qtip/qtip-verify-jobs.yml
jjb/releng/automate.yml
jjb/releng/docker-deploy.sh
jjb/releng/generate-job-list.sh [new file with mode: 0755]
jjb/releng/opnfv-docker-arm.yml
jjb/releng/opnfv-docker.sh
jjb/releng/opnfv-docker.yml
jjb/releng/opnfv-lint.yml
jjb/releng/opnfv-repo-archiver.sh [new file with mode: 0644]
jjb/releng/opnfv-utils.yml
jjb/releng/releng-ci-jobs.yml
jjb/securedlab/check-jinja2.yml
jjb/sfc/sfc-project-jobs.yml [moved from jjb/multisite/multisite-verify-jobs.yml with 81% similarity]
jjb/snaps/snaps-verify-jobs.yml [moved from jjb/snaps/snaps.yml with 78% similarity]
jjb/storperf/storperf-daily-jobs.yml [new file with mode: 0644]
jjb/storperf/storperf-verify-jobs.yml [new file with mode: 0644]
jjb/storperf/storperf.yml
jjb/test-requirements.txt [deleted file]
jjb/xci/bifrost-cleanup-job.yml
jjb/xci/bifrost-periodic-jobs.yml
jjb/xci/bifrost-provision.sh
jjb/xci/bifrost-verify-jobs.yml
jjb/xci/bifrost-verify.sh
jjb/xci/osa-periodic-jobs.yml
jjb/xci/xci-daily-jobs.yml
jjb/xci/xci-deploy.sh
jjb/xci/xci-functest.sh [deleted file]
jjb/xci/xci-verify-jobs.yml [new file with mode: 0644]
jjb/yardstick/yardstick-daily-jobs.yml
jjb/yardstick/yardstick-daily.sh
jjb/yardstick/yardstick-get-k8s-conf.sh [new file with mode: 0755]
modules/setup.cfg [new file with mode: 0644]
modules/setup.py
modules/tox.ini [new file with mode: 0644]
prototypes/bifrost/README.md [deleted file]
prototypes/bifrost/playbooks/opnfv-virtual.yaml [deleted file]
prototypes/bifrost/scripts/bifrost-provision.sh [deleted file]
prototypes/bifrost/scripts/destroy-env.sh [deleted file]
prototypes/openstack-ansible/README.md [deleted file]
prototypes/openstack-ansible/file/cinder.yml [deleted file]
prototypes/openstack-ansible/file/exports [deleted file]
prototypes/openstack-ansible/file/modules [deleted file]
prototypes/openstack-ansible/file/openstack_user_config.yml [deleted file]
prototypes/openstack-ansible/file/opnfv-setup-openstack.yml [deleted file]
prototypes/openstack-ansible/file/user_variables.yml [deleted file]
prototypes/openstack-ansible/playbooks/configure-targethosts.yml [deleted file]
prototypes/openstack-ansible/playbooks/configure-xcimaster.yml [deleted file]
prototypes/openstack-ansible/playbooks/inventory [deleted file]
prototypes/openstack-ansible/scripts/osa-deploy.sh [deleted file]
prototypes/openstack-ansible/template/bifrost/compute.interface.j2 [deleted file]
prototypes/openstack-ansible/template/bifrost/controller.interface.j2 [deleted file]
prototypes/openstack-ansible/var/ubuntu.yml [deleted file]
prototypes/puppet-infracloud/README.md [deleted file]
prototypes/puppet-infracloud/creds/clouds.yaml [deleted file]
prototypes/puppet-infracloud/deploy_on_baremetal.md [deleted file]
prototypes/puppet-infracloud/hiera/common.yaml [deleted file]
prototypes/puppet-infracloud/hiera/common_baremetal.yaml [deleted file]
prototypes/puppet-infracloud/install_modules.sh [deleted file]
prototypes/puppet-infracloud/install_puppet.sh [deleted file]
prototypes/puppet-infracloud/manifests/site.pp [deleted file]
prototypes/puppet-infracloud/modules.env [deleted file]
prototypes/puppet-infracloud/modules/opnfv/manifests/compute.pp [deleted file]
prototypes/puppet-infracloud/modules/opnfv/manifests/controller.pp [deleted file]
prototypes/puppet-infracloud/modules/opnfv/manifests/server.pp [deleted file]
prototypes/xci/README.rst [deleted file]
prototypes/xci/config/aio-vars [deleted file]
prototypes/xci/config/env-vars [deleted file]
prototypes/xci/config/ha-vars [deleted file]
prototypes/xci/config/mini-vars [deleted file]
prototypes/xci/config/noha-vars [deleted file]
prototypes/xci/config/pinned-versions [deleted file]
prototypes/xci/config/user-vars [deleted file]
prototypes/xci/docs/developer-guide.rst [deleted file]
prototypes/xci/file/aio/configure-opnfvhost.yml [deleted file]
prototypes/xci/file/aio/flavor-vars.yml [deleted file]
prototypes/xci/file/aio/inventory [deleted file]
prototypes/xci/file/ansible-role-requirements.yml [deleted file]
prototypes/xci/file/cinder.yml [deleted file]
prototypes/xci/file/ha/flavor-vars.yml [deleted file]
prototypes/xci/file/ha/inventory [deleted file]
prototypes/xci/file/ha/openstack_user_config.yml [deleted file]
prototypes/xci/file/ha/user_variables.yml [deleted file]
prototypes/xci/file/install-ansible.sh [deleted file]
prototypes/xci/file/mini/flavor-vars.yml [deleted file]
prototypes/xci/file/mini/inventory [deleted file]
prototypes/xci/file/mini/openstack_user_config.yml [deleted file]
prototypes/xci/file/mini/user_variables.yml [deleted file]
prototypes/xci/file/noha/flavor-vars.yml [deleted file]
prototypes/xci/file/noha/inventory [deleted file]
prototypes/xci/file/noha/openstack_user_config.yml [deleted file]
prototypes/xci/file/noha/user_variables.yml [deleted file]
prototypes/xci/file/setup-openstack.yml [deleted file]
prototypes/xci/playbooks/configure-localhost.yml [deleted file]
prototypes/xci/playbooks/configure-opnfvhost.yml [deleted file]
prototypes/xci/playbooks/configure-targethosts.yml [deleted file]
prototypes/xci/playbooks/inventory [deleted file]
prototypes/xci/playbooks/provision-vm-nodes.yml [deleted file]
prototypes/xci/playbooks/roles/clone-repository/tasks/main.yml [deleted file]
prototypes/xci/playbooks/roles/configure-network/tasks/main.yml [deleted file]
prototypes/xci/playbooks/roles/configure-nfs/tasks/main.yml [deleted file]
prototypes/xci/playbooks/roles/remove-folders/tasks/main.yml [deleted file]
prototypes/xci/playbooks/roles/synchronize-time/tasks/main.yml [deleted file]
prototypes/xci/scripts/update-osa-version-files.sh [deleted file]
prototypes/xci/template/compute.interface.j2 [deleted file]
prototypes/xci/template/controller.interface.j2 [deleted file]
prototypes/xci/template/opnfv.interface.j2 [deleted file]
prototypes/xci/var/Debian.yml [deleted file]
prototypes/xci/var/RedHat.yml [deleted file]
prototypes/xci/var/Suse.yml [deleted file]
prototypes/xci/var/opnfv.yml [deleted file]
prototypes/xci/xci-deploy.sh [deleted file]
setup.py [deleted file]
tox.ini
utils/create_pod_file.py
utils/fetch_os_creds.sh
utils/push-test-logs.sh
utils/slave-monitor-0.1.sh [new file with mode: 0644]
utils/test/reporting/api/__init__.py [moved from utils/test/reporting/api/api/__init__.py with 100% similarity]
utils/test/reporting/api/conf.py [moved from utils/test/reporting/api/api/conf.py with 100% similarity]
utils/test/reporting/api/handlers/__init__.py [moved from utils/test/reporting/api/api/handlers/__init__.py with 100% similarity]
utils/test/reporting/api/handlers/landing.py [moved from utils/test/reporting/api/api/handlers/landing.py with 69% similarity]
utils/test/reporting/api/handlers/projects.py [moved from utils/test/reporting/api/api/handlers/projects.py with 100% similarity]
utils/test/reporting/api/handlers/testcases.py [moved from utils/test/reporting/api/api/handlers/testcases.py with 100% similarity]
utils/test/reporting/api/requirements.txt [deleted file]
utils/test/reporting/api/server.py [moved from utils/test/reporting/api/api/server.py with 100% similarity]
utils/test/reporting/api/setup.cfg [deleted file]
utils/test/reporting/api/setup.py [deleted file]
utils/test/reporting/api/urls.py [moved from utils/test/reporting/api/api/urls.py with 100% similarity]
utils/test/reporting/docker/Dockerfile
utils/test/reporting/docker/nginx.conf
utils/test/reporting/docker/reporting.sh
utils/test/reporting/docker/supervisor.conf
utils/test/reporting/docker/web_server.sh [new file with mode: 0755]
utils/test/reporting/docs/_build/.buildinfo [new file with mode: 0644]
utils/test/reporting/docs/_build/.doctrees/environment.pickle [new file with mode: 0644]
utils/test/reporting/docs/_build/.doctrees/index.doctree [new file with mode: 0644]
utils/test/reporting/docs/conf.py [new file with mode: 0644]
utils/test/reporting/docs/index.rst [new file with mode: 0644]
utils/test/reporting/pages/angular.sh
utils/test/reporting/pages/app/index.html
utils/test/reporting/pages/app/scripts/controllers/table.controller.js
utils/test/reporting/pages/app/scripts/controllers/testvisual.controller.js
utils/test/reporting/pages/app/scripts/factory/table.factory.js
utils/test/reporting/pages/app/views/commons/table.html
utils/test/reporting/pages/config.sh [new file with mode: 0755]
utils/test/reporting/reporting/__init__.py [moved from utils/test/reporting/functest/__init__.py with 100% similarity]
utils/test/reporting/reporting/bottlenecks/__init__.py [moved from utils/test/reporting/qtip/__init__.py with 100% similarity]
utils/test/reporting/reporting/bottlenecks/reporting-status.py [new file with mode: 0644]
utils/test/reporting/reporting/bottlenecks/template/index-status-tmpl.html [new file with mode: 0644]
utils/test/reporting/reporting/functest/__init__.py [moved from utils/test/reporting/tests/__init__.py with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_0.png [moved from utils/test/reporting/functest/img/gauge_0.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_100.png [moved from utils/test/reporting/functest/img/gauge_100.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_16.7.png [moved from utils/test/reporting/functest/img/gauge_16.7.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_25.png [moved from utils/test/reporting/functest/img/gauge_25.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_33.3.png [moved from utils/test/reporting/functest/img/gauge_33.3.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_41.7.png [moved from utils/test/reporting/functest/img/gauge_41.7.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_50.png [moved from utils/test/reporting/functest/img/gauge_50.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_58.3.png [moved from utils/test/reporting/functest/img/gauge_58.3.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_66.7.png [moved from utils/test/reporting/functest/img/gauge_66.7.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_75.png [moved from utils/test/reporting/functest/img/gauge_75.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_8.3.png [moved from utils/test/reporting/functest/img/gauge_8.3.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_83.3.png [moved from utils/test/reporting/functest/img/gauge_83.3.png with 100% similarity]
utils/test/reporting/reporting/functest/img/gauge_91.7.png [moved from utils/test/reporting/functest/img/gauge_91.7.png with 100% similarity]
utils/test/reporting/reporting/functest/img/icon-nok.png [moved from utils/test/reporting/functest/img/icon-nok.png with 100% similarity]
utils/test/reporting/reporting/functest/img/icon-ok.png [moved from utils/test/reporting/functest/img/icon-ok.png with 100% similarity]
utils/test/reporting/reporting/functest/img/weather-clear.png [moved from utils/test/reporting/functest/img/weather-clear.png with 100% similarity]
utils/test/reporting/reporting/functest/img/weather-few-clouds.png [moved from utils/test/reporting/functest/img/weather-few-clouds.png with 100% similarity]
utils/test/reporting/reporting/functest/img/weather-overcast.png [moved from utils/test/reporting/functest/img/weather-overcast.png with 100% similarity]
utils/test/reporting/reporting/functest/img/weather-storm.png [moved from utils/test/reporting/functest/img/weather-storm.png with 100% similarity]
utils/test/reporting/reporting/functest/index.html [moved from utils/test/reporting/functest/index.html with 100% similarity]
utils/test/reporting/reporting/functest/reporting-status.py [moved from utils/test/reporting/functest/reporting-status.py with 95% similarity]
utils/test/reporting/reporting/functest/reporting-tempest.py [moved from utils/test/reporting/functest/reporting-tempest.py with 64% similarity]
utils/test/reporting/reporting/functest/reporting-vims.py [moved from utils/test/reporting/functest/reporting-vims.py with 97% similarity]
utils/test/reporting/reporting/functest/scenarioResult.py [moved from utils/test/reporting/functest/scenarioResult.py with 100% similarity]
utils/test/reporting/reporting/functest/template/index-status-tmpl.html [moved from utils/test/reporting/functest/template/index-status-tmpl.html with 82% similarity]
utils/test/reporting/reporting/functest/template/index-tempest-tmpl.html [moved from utils/test/reporting/functest/template/index-tempest-tmpl.html with 100% similarity]
utils/test/reporting/reporting/functest/template/index-vims-tmpl.html [moved from utils/test/reporting/functest/template/index-vims-tmpl.html with 100% similarity]
utils/test/reporting/reporting/functest/testCase.py [moved from utils/test/reporting/functest/testCase.py with 100% similarity]
utils/test/reporting/reporting/qtip/__init__.py [moved from utils/test/reporting/tests/unit/__init__.py with 100% similarity]
utils/test/reporting/reporting/qtip/index.html [moved from utils/test/reporting/qtip/index.html with 100% similarity]
utils/test/reporting/reporting/qtip/reporting-status.py [moved from utils/test/reporting/qtip/reporting-status.py with 94% similarity]
utils/test/reporting/reporting/qtip/template/index-status-tmpl.html [moved from utils/test/reporting/qtip/template/index-status-tmpl.html with 92% similarity]
utils/test/reporting/reporting/reporting.yaml [moved from utils/test/reporting/reporting.yaml with 91% similarity]
utils/test/reporting/reporting/storperf/__init__.py [moved from utils/test/reporting/tests/unit/utils/__init__.py with 100% similarity]
utils/test/reporting/reporting/storperf/reporting-status.py [moved from utils/test/reporting/storperf/reporting-status.py with 95% similarity]
utils/test/reporting/reporting/storperf/template/index-status-tmpl.html [moved from utils/test/reporting/storperf/template/index-status-tmpl.html with 100% similarity]
utils/test/reporting/reporting/tests/__init__.py [moved from utils/test/reporting/utils/__init__.py with 100% similarity]
utils/test/reporting/reporting/tests/unit/__init__.py [moved from prototypes/puppet-infracloud/.gitkeep with 100% similarity]
utils/test/reporting/reporting/tests/unit/utils/__init__.py [moved from utils/test/reporting/pages/app/scripts/app.config.js with 100% similarity]
utils/test/reporting/reporting/tests/unit/utils/test_utils.py [moved from utils/test/reporting/tests/unit/utils/test_utils.py with 78% similarity]
utils/test/reporting/reporting/utils/__init__.py [new file with mode: 0644]
utils/test/reporting/reporting/utils/reporting_utils.py [moved from utils/test/reporting/utils/reporting_utils.py with 66% similarity]
utils/test/reporting/reporting/utils/scenarioResult.py [moved from utils/test/reporting/utils/scenarioResult.py with 100% similarity]
utils/test/reporting/reporting/vsperf/__init__.py [new file with mode: 0644]
utils/test/reporting/reporting/vsperf/reporting-status.py [new file with mode: 0644]
utils/test/reporting/reporting/vsperf/template/index-status-tmpl.html [new file with mode: 0644]
utils/test/reporting/reporting/yardstick/__init__.py [new file with mode: 0644]
utils/test/reporting/reporting/yardstick/img/gauge_0.png [moved from utils/test/reporting/yardstick/img/gauge_0.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_100.png [moved from utils/test/reporting/yardstick/img/gauge_100.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_16.7.png [moved from utils/test/reporting/yardstick/img/gauge_16.7.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_25.png [moved from utils/test/reporting/yardstick/img/gauge_25.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_33.3.png [moved from utils/test/reporting/yardstick/img/gauge_33.3.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_41.7.png [moved from utils/test/reporting/yardstick/img/gauge_41.7.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_50.png [moved from utils/test/reporting/yardstick/img/gauge_50.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_58.3.png [moved from utils/test/reporting/yardstick/img/gauge_58.3.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_66.7.png [moved from utils/test/reporting/yardstick/img/gauge_66.7.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_75.png [moved from utils/test/reporting/yardstick/img/gauge_75.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_8.3.png [moved from utils/test/reporting/yardstick/img/gauge_8.3.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_83.3.png [moved from utils/test/reporting/yardstick/img/gauge_83.3.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/gauge_91.7.png [moved from utils/test/reporting/yardstick/img/gauge_91.7.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/icon-nok.png [moved from utils/test/reporting/yardstick/img/icon-nok.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/icon-ok.png [moved from utils/test/reporting/yardstick/img/icon-ok.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/weather-clear.png [moved from utils/test/reporting/yardstick/img/weather-clear.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/weather-few-clouds.png [moved from utils/test/reporting/yardstick/img/weather-few-clouds.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/weather-overcast.png [moved from utils/test/reporting/yardstick/img/weather-overcast.png with 100% similarity]
utils/test/reporting/reporting/yardstick/img/weather-storm.png [moved from utils/test/reporting/yardstick/img/weather-storm.png with 100% similarity]
utils/test/reporting/reporting/yardstick/index.html [moved from utils/test/reporting/yardstick/index.html with 100% similarity]
utils/test/reporting/reporting/yardstick/reporting-status.py [moved from utils/test/reporting/yardstick/reporting-status.py with 96% similarity]
utils/test/reporting/reporting/yardstick/scenarios.py [moved from utils/test/reporting/yardstick/scenarios.py with 100% similarity]
utils/test/reporting/reporting/yardstick/template/index-status-tmpl.html [moved from utils/test/reporting/yardstick/template/index-status-tmpl.html with 100% similarity]
utils/test/reporting/requirements.txt [new file with mode: 0644]
utils/test/reporting/run_test.sh
utils/test/reporting/setup.cfg [new file with mode: 0644]
utils/test/reporting/setup.py
utils/test/reporting/test-requirements.txt [new file with mode: 0644]
utils/test/reporting/tox.ini [new file with mode: 0644]
utils/test/testapi/.gitignore [new file with mode: 0644]
utils/test/testapi/3rd_party/static/testapi-ui/app.js
utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/guidelines.html [deleted file]
utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/guidelinesController.js [deleted file]
utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/partials/guidelineDetails.html [deleted file]
utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/partials/testListModal.html [deleted file]
utils/test/testapi/3rd_party/static/testapi-ui/components/pods/pods.html [new file with mode: 0644]
utils/test/testapi/3rd_party/static/testapi-ui/components/pods/podsController.js [new file with mode: 0644]
utils/test/testapi/3rd_party/static/testapi-ui/components/profile/profile.html
utils/test/testapi/3rd_party/static/testapi-ui/components/profile/profileController.js
utils/test/testapi/3rd_party/static/testapi-ui/components/results/results.html
utils/test/testapi/3rd_party/static/testapi-ui/components/results/resultsController.js
utils/test/testapi/3rd_party/static/testapi-ui/config.json
utils/test/testapi/3rd_party/static/testapi-ui/index.html
utils/test/testapi/3rd_party/static/testapi-ui/shared/header/header.html
utils/test/testapi/MANIFEST.in [new file with mode: 0644]
utils/test/testapi/deployment/deploy.py
utils/test/testapi/deployment/docker-compose.yml.template
utils/test/testapi/docker/Dockerfile
utils/test/testapi/docker/prepare-env.sh
utils/test/testapi/etc/config.ini
utils/test/testapi/htmlize/htmlize.py
utils/test/testapi/install.sh [deleted file]
utils/test/testapi/opnfv_testapi/cmd/server.py
utils/test/testapi/opnfv_testapi/common/check.py
utils/test/testapi/opnfv_testapi/common/config.py
utils/test/testapi/opnfv_testapi/common/constants.py [new file with mode: 0644]
utils/test/testapi/opnfv_testapi/common/message.py
utils/test/testapi/opnfv_testapi/common/raises.py
utils/test/testapi/opnfv_testapi/db/__init__.py [new file with mode: 0644]
utils/test/testapi/opnfv_testapi/db/api.py [new file with mode: 0644]
utils/test/testapi/opnfv_testapi/resources/handlers.py
utils/test/testapi/opnfv_testapi/resources/models.py
utils/test/testapi/opnfv_testapi/resources/result_handlers.py
utils/test/testapi/opnfv_testapi/resources/result_models.py
utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py
utils/test/testapi/opnfv_testapi/resources/scenario_models.py
utils/test/testapi/opnfv_testapi/router/url_mappings.py
utils/test/testapi/opnfv_testapi/tests/unit/common/noparam.ini [deleted file]
utils/test/testapi/opnfv_testapi/tests/unit/common/normal.ini [deleted file]
utils/test/testapi/opnfv_testapi/tests/unit/common/nosection.ini [deleted file]
utils/test/testapi/opnfv_testapi/tests/unit/common/notboolean.ini [deleted file]
utils/test/testapi/opnfv_testapi/tests/unit/common/notint.ini [deleted file]
utils/test/testapi/opnfv_testapi/tests/unit/common/test_config.py
utils/test/testapi/opnfv_testapi/tests/unit/conftest.py [new file with mode: 0644]
utils/test/testapi/opnfv_testapi/tests/unit/executor.py
utils/test/testapi/opnfv_testapi/tests/unit/fake_pymongo.py
utils/test/testapi/opnfv_testapi/tests/unit/resources/__init__.py [new file with mode: 0644]
utils/test/testapi/opnfv_testapi/tests/unit/resources/scenario-c1.json [moved from utils/test/testapi/opnfv_testapi/tests/unit/scenario-c1.json with 100% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/resources/scenario-c2.json [moved from utils/test/testapi/opnfv_testapi/tests/unit/scenario-c2.json with 96% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/resources/test_base.py [moved from utils/test/testapi/opnfv_testapi/tests/unit/test_base.py with 75% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/resources/test_fake_pymongo.py [moved from utils/test/testapi/opnfv_testapi/tests/unit/test_fake_pymongo.py with 100% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/resources/test_pod.py [moved from utils/test/testapi/opnfv_testapi/tests/unit/test_pod.py with 97% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/resources/test_project.py [moved from utils/test/testapi/opnfv_testapi/tests/unit/test_project.py with 98% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/resources/test_result.py [moved from utils/test/testapi/opnfv_testapi/tests/unit/test_result.py with 83% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/resources/test_scenario.py [new file with mode: 0644]
utils/test/testapi/opnfv_testapi/tests/unit/resources/test_testcase.py [moved from utils/test/testapi/opnfv_testapi/tests/unit/test_testcase.py with 99% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/resources/test_token.py [moved from utils/test/testapi/opnfv_testapi/tests/unit/test_token.py with 96% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/resources/test_version.py [moved from utils/test/testapi/opnfv_testapi/tests/unit/test_version.py with 94% similarity]
utils/test/testapi/opnfv_testapi/tests/unit/test_scenario.py [deleted file]
utils/test/testapi/opnfv_testapi/tornado_swagger/swagger.py
utils/test/testapi/opnfv_testapi/ui/auth/base.py [deleted file]
utils/test/testapi/opnfv_testapi/ui/auth/constants.py [deleted file]
utils/test/testapi/opnfv_testapi/ui/auth/sign.py
utils/test/testapi/opnfv_testapi/ui/auth/user.py
utils/test/testapi/opnfv_testapi/ui/root.py
utils/test/testapi/requirements.txt
utils/test/testapi/run_test.sh [deleted file]
utils/test/testapi/setup.cfg
utils/test/testapi/setup.py
utils/test/testapi/test-requirements.txt
utils/test/testapi/tools/watchdog/docker_watch.sh [new file with mode: 0644]
utils/test/testapi/tox.ini
utils/test/testapi/update/templates/backup_mongodb.py
utils/test/testapi/update/templates/update_mongodb.py
utils/test/vnfcatalogue/VNF_Catalogue/.dockerignore [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/Dockerfile [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/README.md [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/app.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/bin/www [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/database.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/docker-compose.yml [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/docker_commands.sh [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/migration/3rd_party/wait-for-it/LICENSE [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/migration/3rd_party/wait-for-it/README.md [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/migration/3rd_party/wait-for-it/wait-for-it.sh [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/migration/Dockerfile [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/migration/migrate.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/migration/package.json [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/migration/schema.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/package.json [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/.DS_Store [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/LICENSE [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/README.md [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/css/materialize.css [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/css/materialize.min.css [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/.DS_Store [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.eot [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.ttf [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.woff [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.woff2 [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.eot [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.ttf [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.woff [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.woff2 [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.eot [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.ttf [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.woff [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.woff2 [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.eot [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.ttf [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.woff [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.woff2 [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.eot [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.ttf [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.woff [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.woff2 [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/js/materialize.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/js/materialize.min.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/typeahead.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/images/3rd_party/commits.png [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/images/logo.png [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/javascripts/global.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/javascripts/mode_edit.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/javascripts/search_results.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/3rd_party/bootstrap.css [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/project_profile.css [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/search_form.css [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/search_projects.css [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/style.css [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/public/uploads/logo.png [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/routes/add_project.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/routes/add_tag.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/routes/index.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/routes/project_profile.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/routes/search_projects.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/routes/search_tag.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/routes/search_vnf.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/routes/vnf_tag_association.js [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/views/add_project.jade [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/views/error.jade [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/views/index.jade [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/views/layout.jade [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/views/project_profile.jade [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/views/search.jade [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/views/search_projects.jade [deleted file]
utils/test/vnfcatalogue/VNF_Catalogue/views/vnf_tag_association.jade [deleted file]
utils/test/vnfcatalogue/cronjobs/README.md [deleted file]
utils/test/vnfcatalogue/cronjobs/database.js [deleted file]
utils/test/vnfcatalogue/cronjobs/github.js [deleted file]
utils/test/vnfcatalogue/helpers/README.md [deleted file]
utils/test/vnfcatalogue/helpers/migrate.js [deleted file]
utils/test/vnfcatalogue/helpers/schema.js [deleted file]
utils/upload-artifact.sh [new file with mode: 0644]

diff --git a/.yamllint b/.yamllint
new file mode 100644 (file)
index 0000000..4402f17
--- /dev/null
+++ b/.yamllint
@@ -0,0 +1,8 @@
+---
+extends: default
+
+rules:
+  # 120 chars should be enough and don't fail if a line is longer
+  line-length:
+    max: 120
+    level: warning
diff --git a/INFO b/INFO
index 0fb3582..38ac5b3 100644 (file)
--- a/INFO
+++ b/INFO
@@ -9,6 +9,7 @@ Jira Project Prefix: RELENG
 Mailing list tag: [releng]
 IRC: Server:freenode.net Channel:#opnfv-octopus
 Repository: releng
+Other Repositories: releng-xci
 
 Committers:
 Fatih Degirmenci (Ericsson, fatih.degirmenci@ericsson.com)
index 97fea89..f5aab1a 100644 (file)
@@ -56,3 +56,4 @@
     publishers:
         - archive-artifacts:
             artifacts: 'job_output/*'
+        - email-jenkins-admins-on-failure
index a937acb..01017f3 100644 (file)
@@ -1,37 +1,39 @@
+---
 - project:
     name: 'netvirt'
 
     project: 'netvirt'
 
     installer: 'netvirt'
-#####################################
-# branch definitions
-#####################################
+    #####################################
+    # branch definitions
+    #####################################
     stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
-            disabled: false
-        - carbon:
-            branch: 'stable/carbon'
-            gs-pathname: ''
-            disabled: false
-#####################################
-# patch verification phases
-#####################################
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
+      - carbon:
+          branch: 'stable/carbon'
+          gs-pathname: ''
+          disabled: false
+    #####################################
+    # patch verification phases
+    #####################################
     phase:
-        - 'create-apex-vms':
-            slave-label: 'odl-netvirt-virtual-intel'
-        - 'install-netvirt':
-            slave-label: 'odl-netvirt-virtual-intel'
-        - 'postprocess':
-            slave-label: 'odl-netvirt-virtual-intel'
-#####################################
-# jobs
-#####################################
+      - 'create-apex-vms':
+          slave-label: 'odl-netvirt-virtual-intel'
+      - 'install-netvirt':
+          slave-label: 'odl-netvirt-virtual-intel'
+      - 'postprocess':
+          slave-label: 'odl-netvirt-virtual-intel'
+    #####################################
+    # jobs
+    #####################################
     jobs:
-        - 'odl-netvirt-verify-virtual-{stream}'
-        - 'odl-netvirt-verify-virtual-{phase}-{stream}'
+      - 'odl-netvirt-verify-virtual-{stream}'
+      - 'odl-netvirt-verify-virtual-{phase}-{stream}'
+
 #####################################
 # job templates
 #####################################
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 5
-            max-per-node: 1
-            option: 'project'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 5
+          max-per-node: 1
+          option: 'project'
 
     scm:
-        - git:
-            url: https://gerrit.opnfv.org/gerrit/apex
-            branches:
-                - 'origin/master'
-            timeout: 15
-            wipe-workspace: true
+      - git:
+          url: https://gerrit.opnfv.org/gerrit/apex
+          branches:
+            - 'origin/master'
+          timeout: 15
+          wipe-workspace: true
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - string:
-            name: NETVIRT_ARTIFACT
-            default: distribution-karaf.tar.gz
-        - 'odl-netvirt-virtual-intel-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - string:
+          name: NETVIRT_ARTIFACT
+          default: distribution-karaf.tar.gz
+      - 'odl-netvirt-virtual-intel-defaults'
 
     triggers:
-        - gerrit:
-            server-name: 'git.opendaylight.org'
-            trigger-on:
- #               - comment-added-contains-event:
- #                   comment-contains-value: 'https://jenkins.opendaylight.org/releng/job/netvirt-patch-test-current-carbon/.*?/ : SUCCESS'
- #               - comment-added-contains-event:
- #                   comment-contains-value: 'https://jenkins.opendaylight.org/releng/job/netvirt-patch-test-current-carbon/.*?/ : UNSTABLE'
-                - comment-added-contains-event:
-                    comment-contains-value: 'opnfv-test'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-            readable-message: true
+      - gerrit:
+          server-name: 'git.opendaylight.org'
+          trigger-on:
+            # yamllint disable rule:line-length
+            # - comment-added-contains-event:
+            #     comment-contains-value: 'https://jenkins.opendaylight.org/releng/job/netvirt-patch-test-current-carbon/.*?/ : SUCCESS'
+            # - comment-added-contains-event:
+            #     comment-contains-value: 'https://jenkins.opendaylight.org/releng/job/netvirt-patch-test-current-carbon/.*?/ : UNSTABLE'
+            # yamllint enable rule:line-length
+            - comment-added-contains-event:
+                comment-contains-value: 'opnfv-test'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+          readable-message: true
 
     builders:
-        - description-setter:
-            description: "Built on $NODE_NAME"
-        - multijob:
-            name: create-apex-vms
-            condition: SUCCESSFUL
-            projects:
-                - name: 'odl-netvirt-verify-virtual-create-apex-vms-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    BRANCH=$BRANCH
-                    GERRIT_REFSPEC=$GERRIT_REFSPEC
-                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
-                    GERRIT_CHANGE_ID=$GERRIT_CHANGE_ID
-                    GERRIT_PATCHSET_NUMBER=$GERRIT_PATCHSET_NUMBER
-                    GERRIT_PATCHSET_REVISION=$GERRIT_PATCHSET_REVISION
-                    NETVIRT_ARTIFACT=$NETVIRT_ARTIFACT
-                    APEX_ENV_NUMBER=$APEX_ENV_NUMBER
-                  node-parameters: true
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-        - multijob:
-            name: install-netvirt
-            condition: SUCCESSFUL
-            projects:
-                - name: 'odl-netvirt-verify-virtual-install-netvirt-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    ODL_BRANCH={branch}
-                    BRANCH=$BRANCH
-                    GERRIT_REFSPEC=$GERRIT_REFSPEC
-                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
-                    GERRIT_CHANGE_ID=$GERRIT_CHANGE_ID
-                    GERRIT_PATCHSET_NUMBER=$GERRIT_PATCHSET_NUMBER
-                    GERRIT_PATCHSET_REVISION=$GERRIT_PATCHSET_REVISION
-                    NETVIRT_ARTIFACT=$NETVIRT_ARTIFACT
-                  node-parameters: true
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-        - multijob:
-            name: functest
-            condition: SUCCESSFUL
-            projects:
-                - name: 'functest-netvirt-virtual-suite-master'
-                  predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-nofeature-ha
-                    FUNCTEST_SUITE_NAME=odl_netvirt
-                    RC_FILE_PATH=$HOME/cloner-info/overcloudrc
-                  node-parameters: true
-                  kill-phase-on: FAILURE
-                  abort-all-job: false
-        - multijob:
-            name: postprocess
-            condition: ALWAYS
-            projects:
-                - name: 'odl-netvirt-verify-virtual-postprocess-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    BRANCH=$BRANCH
-                    GERRIT_REFSPEC=$GERRIT_REFSPEC
-                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
-                    GERRIT_CHANGE_ID=$GERRIT_CHANGE_ID
-                    GERRIT_PATCHSET_NUMBER=$GERRIT_PATCHSET_NUMBER
-                    GERRIT_PATCHSET_REVISION=$GERRIT_PATCHSET_REVISION
-                    NETVIRT_ARTIFACT=$NETVIRT_ARTIFACT
-                  node-parameters: true
-                  kill-phase-on: FAILURE
-                  abort-all-job: false
+      - description-setter:
+          description: "Built on $NODE_NAME"
+      - multijob:
+          name: create-apex-vms
+          condition: SUCCESSFUL
+          projects:
+            - name: 'odl-netvirt-verify-virtual-create-apex-vms-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                BRANCH=$BRANCH
+                GERRIT_REFSPEC=$GERRIT_REFSPEC
+                GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                GERRIT_CHANGE_ID=$GERRIT_CHANGE_ID
+                GERRIT_PATCHSET_NUMBER=$GERRIT_PATCHSET_NUMBER
+                GERRIT_PATCHSET_REVISION=$GERRIT_PATCHSET_REVISION
+                NETVIRT_ARTIFACT=$NETVIRT_ARTIFACT
+                APEX_ENV_NUMBER=$APEX_ENV_NUMBER
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: true
+      - multijob:
+          name: install-netvirt
+          condition: SUCCESSFUL
+          projects:
+            - name: 'odl-netvirt-verify-virtual-install-netvirt-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                ODL_BRANCH={branch}
+                BRANCH=$BRANCH
+                GERRIT_REFSPEC=$GERRIT_REFSPEC
+                GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                GERRIT_CHANGE_ID=$GERRIT_CHANGE_ID
+                GERRIT_PATCHSET_NUMBER=$GERRIT_PATCHSET_NUMBER
+                GERRIT_PATCHSET_REVISION=$GERRIT_PATCHSET_REVISION
+                NETVIRT_ARTIFACT=$NETVIRT_ARTIFACT
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: true
+      - multijob:
+          name: functest
+          condition: SUCCESSFUL
+          projects:
+            - name: 'functest-netvirt-virtual-suite-master'
+              predefined-parameters: |
+                DEPLOY_SCENARIO=os-odl_l3-nofeature-ha
+                FUNCTEST_SUITE_NAME=odl_netvirt
+                RC_FILE_PATH=$HOME/cloner-info/overcloudrc
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: false
+      - multijob:
+          name: postprocess
+          condition: ALWAYS
+          projects:
+            - name: 'odl-netvirt-verify-virtual-postprocess-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                BRANCH=$BRANCH
+                GERRIT_REFSPEC=$GERRIT_REFSPEC
+                GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                GERRIT_CHANGE_ID=$GERRIT_CHANGE_ID
+                GERRIT_PATCHSET_NUMBER=$GERRIT_PATCHSET_NUMBER
+                GERRIT_PATCHSET_REVISION=$GERRIT_PATCHSET_REVISION
+                NETVIRT_ARTIFACT=$NETVIRT_ARTIFACT
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: false
 
 - job-template:
     name: 'odl-netvirt-verify-virtual-{phase}-{stream}'
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 5
-            max-per-node: 1
-            option: 'project'
-        - build-blocker:
-            use-build-blocker: true
-            blocking-jobs:
-                - 'odl-netvirt-verify-virtual-create-apex-vms-.*'
-                - 'odl-netvirt-verify-virtual-install-netvirt-.*'
-                - 'functest-netvirt-virtual-suite-.*'
-                - 'odl-netvirt-verify-virtual-postprocess-.*'
-            block-level: 'NODE'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 5
+          max-per-node: 1
+          option: 'project'
+      - build-blocker:
+          use-build-blocker: true
+          blocking-jobs:
+            - 'odl-netvirt-verify-virtual-create-apex-vms-.*'
+            - 'odl-netvirt-verify-virtual-install-netvirt-.*'
+            - 'functest-netvirt-virtual-suite-.*'
+            - 'odl-netvirt-verify-virtual-postprocess-.*'
+          block-level: 'NODE'
 
     wrappers:
-        - ssh-agent-wrapper
-        - timeout:
-            timeout: 360
-            fail: true
+      - ssh-agent-wrapper
+      - timeout:
+          timeout: 360
+          fail: true
 
     scm:
-        - git:
-            url: https://gerrit.opnfv.org/gerrit/apex
-            branches:
-                - 'origin/master'
-            timeout: 15
-            wipe-workspace: true
+      - git:
+          url: https://gerrit.opnfv.org/gerrit/apex
+          branches:
+            - 'origin/master'
+          timeout: 15
+          wipe-workspace: true
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - '{slave-label}-defaults'
-        - '{installer}-defaults'
-        - string:
-            name: DEPLOY_SCENARIO
-            default: 'os-odl_l2-bgpvpn-noha'
-            description: 'Scenario to deploy and test'
-        - string:
-            name: GS_URL
-            default: artifacts.opnfv.org/apex
-            description: "URL to Google Storage with snapshot artifacts."
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - '{slave-label}-defaults'
+      - '{installer}-defaults'
+      - string:
+          name: DEPLOY_SCENARIO
+          default: 'os-odl_l2-bgpvpn-noha'
+          description: 'Scenario to deploy and test'
+      - string:
+          name: GS_URL
+          default: artifacts.opnfv.org/apex
+          description: "URL to Google Storage with snapshot artifacts."
 
     builders:
-        - description-setter:
-            description: "Built on $NODE_NAME"
-        - '{project}-verify-{phase}-builder'
+      - description-setter:
+          description: "Built on $NODE_NAME"
+      - '{project}-verify-{phase}-builder'
 #####################################
 # builder macros
 #####################################
 - builder:
     name: 'netvirt-verify-create-apex-vms-builder'
     builders:
-        - shell:
-            !include-raw: ../apex/apex-snapshot-deploy.sh
+      - shell:
+          !include-raw: ../apex/apex-snapshot-deploy.sh
 - builder:
     name: 'netvirt-verify-install-netvirt-builder'
     builders:
-        - shell:
-            !include-raw: ./download-netvirt-artifact.sh
-        - shell:
-            !include-raw: ./install-netvirt.sh
+      - shell:
+          !include-raw: ./download-netvirt-artifact.sh
+      - shell:
+          !include-raw: ./install-netvirt.sh
 - builder:
     name: 'netvirt-verify-postprocess-builder'
     builders:
-        - shell:
-            !include-raw: ./postprocess-netvirt.sh
+      - shell:
+          !include-raw: ./postprocess-netvirt.sh
index 58d9f1a..ad94ba3 100755 (executable)
@@ -28,8 +28,10 @@ fi
 BUILD_DIRECTORY=${WORKSPACE}/build
 
 # start the build
-cd $WORKSPACE/ci
-./build.sh $BUILD_ARGS
+pushd ${BUILD_DIRECTORY}
+make clean
+popd
+python3 apex/build.py $BUILD_ARGS
 RPM_VERSION=$(grep Version: $WORKSPACE/build/rpm_specs/opnfv-apex.spec | awk '{ print $2 }')-$(echo $OPNFV_ARTIFACT_VERSION | tr -d '_-')
 # list the contents of BUILD_OUTPUT directory
 echo "Build Directory is ${BUILD_DIRECTORY}/../.build"
index 3a2ca60..a47e3a5 100755 (executable)
@@ -3,7 +3,6 @@ set -o errexit
 set -o nounset
 set -o pipefail
 
-APEX_PKGS="common undercloud onos"
 IPV6_FLAG=False
 
 # log info to console
@@ -11,6 +10,8 @@ echo "Starting the Apex deployment."
 echo "--------------------------------------------------------"
 echo
 
+sudo rm -rf /tmp/tmp*
+
 if [ -z "$DEPLOY_SCENARIO" ]; then
   echo "Deploy scenario not set!"
   exit 1
@@ -36,7 +37,7 @@ if [[ "$ARTIFACT_VERSION" =~ dev ]]; then
   # Settings for deploying from git workspace
   DEPLOY_SETTINGS_DIR="${WORKSPACE}/config/deploy"
   NETWORK_SETTINGS_DIR="${WORKSPACE}/config/network"
-  DEPLOY_CMD="${WORKSPACE}/ci/deploy.sh"
+  DEPLOY_CMD="opnfv-deploy --image-dir ${WORKSPACE}/.build"
   CLEAN_CMD="${WORKSPACE}/ci/clean.sh"
   RESOURCES="${WORKSPACE}/.build/"
   CONFIG="${WORKSPACE}/build"
@@ -47,6 +48,11 @@ if [[ "$ARTIFACT_VERSION" =~ dev ]]; then
   # Ensure artifacts were downloaded and extracted correctly
   # TODO(trozet) add verification here
 
+  # Install dev build
+  mkdir -p ~/tmp
+  mv -f .build ~/tmp/
+  sudo pip3 install --upgrade --force-reinstall .
+  mv -f ~/tmp/.build .
 else
   DEPLOY_SETTINGS_DIR="/etc/opnfv-apex/"
   NETWORK_SETTINGS_DIR="/etc/opnfv-apex/"
@@ -57,12 +63,17 @@ else
   BASE=$CONFIG
   IMAGES=$RESOURCES
   LIB="/var/opt/opnfv/lib"
-
+  sudo mkdir -p /var/log/apex
+  sudo chmod 777 /var/log/apex
+  cd /var/log/apex
 fi
 
 # Install Dependencies
 # Make sure python34 dependencies are installed
-for dep_pkg in epel-release python34 python34-PyYAML python34-setuptools; do
+dependencies="epel-release python34 python34-devel libvirt-devel python34-pip \
+ansible python34-PyYAML python34-jinja2 python34-setuptools python-tox ansible"
+
+for dep_pkg in $dependencies; do
   if ! rpm -q ${dep_pkg} > /dev/null; then
     if ! sudo yum install -y ${dep_pkg}; then
       echo "Failed to install ${dep_pkg}"
@@ -71,31 +82,12 @@ for dep_pkg in epel-release python34 python34-PyYAML python34-setuptools; do
   fi
 done
 
-# Make sure jinja2 is installed
-for python_pkg in jinja2; do
-  if ! python3.4 -c "import $python_pkg"; then
-    echo "$python_pkg package not found for python3.4, attempting to install..."
-    if ! sudo easy_install-3.4 $python_pkg; then
-      echo -e "Failed to install $python_pkg package for python3.4"
-      exit 1
-    fi
-  fi
-done
-
 if [[ "$JOB_NAME" =~ "virtual" ]]; then
   # Make sure ipxe-roms-qemu package is updated to latest.
   # This package is needed for multi virtio nic PXE boot in virtual environment.
   sudo yum update -y ipxe-roms-qemu
-  if [ -z ${PYTHONPATH:-} ]; then
-    export PYTHONPATH=${WORKSPACE}/lib/python
-  else
-    export PYTHONPATH=$PYTHONPATH:${WORKSPACE}/lib/python
-  fi
 fi
 
-# set env vars to deploy cmd
-DEPLOY_CMD="BASE=${BASE} IMAGES=${IMAGES} LIB=${LIB} ${DEPLOY_CMD}"
-
 if [ "$OPNFV_CLEAN" == 'yes' ]; then
   if sudo test -e '/root/inventory/pod_settings.yaml'; then
     clean_opts='-i /root/inventory/pod_settings.yaml'
@@ -103,7 +95,7 @@ if [ "$OPNFV_CLEAN" == 'yes' ]; then
     clean_opts=''
   fi
 
-  sudo BASE=${BASE} LIB=${LIB} ${CLEAN_CMD} ${clean_opts}
+  sudo ${CLEAN_CMD} ${clean_opts}
 fi
 
 if echo ${DEPLOY_SCENARIO} | grep ipv6; then
index 52c3c67..a11fb65 100755 (executable)
@@ -3,8 +3,6 @@ set -o errexit
 set -o nounset
 set -o pipefail
 
-APEX_PKGS="common undercloud onos"
-
 # log info to console
 echo "Downloading the Apex artifact. This could take some time..."
 echo "--------------------------------------------------------"
@@ -23,7 +21,7 @@ if [[ "$ARTIFACT_VERSION" =~ dev ]]; then
   tar -xvf apex-${OPNFV_ARTIFACT_VERSION}.tar.gz
   popd > /dev/null
 else
-  echo "Will download RPMs..."
+  echo "Will use RPMs..."
 
   # Must be RPMs/ISO
   echo "Downloading latest properties file"
@@ -35,14 +33,13 @@ else
   source $BUILD_DIRECTORY/opnfv.properties
 
   RPM_INSTALL_PATH=$(echo "http://"$OPNFV_RPM_URL | sed 's/\/'"$(basename $OPNFV_RPM_URL)"'//')
-  RPM_LIST=${RPM_INSTALL_PATH}/$(basename $OPNFV_RPM_URL)
+  RPM_LIST=$(basename $OPNFV_RPM_URL)
 
   # find version of RPM
   VERSION_EXTENSION=$(echo $(basename $RPM_LIST) | grep -Eo '[0-9]+\.[0-9]+-([0-9]{8}|[a-z]+-[0-9]\.[0-9]+)')
   # build RPM List which already includes base Apex RPM
-  for pkg in ${APEX_PKGS}; do
-    RPM_LIST+=" ${RPM_INSTALL_PATH}/opnfv-apex-${pkg}-${VERSION_EXTENSION}.noarch.rpm"
-  done
+  RPM_LIST+=" opnfv-apex-undercloud-${VERSION_EXTENSION}.noarch.rpm"
+  RPM_LIST+=" python34-opnfv-apex-${VERSION_EXTENSION}.noarch.rpm"
 
   # remove old / install new RPMs
   if rpm -q opnfv-apex > /dev/null; then
@@ -51,10 +48,20 @@ else
       sudo yum remove -y ${INSTALLED_RPMS}
     fi
   fi
+  # Create an rpms dir on slave
+  mkdir -p ~/apex_rpms
+  pushd ~/apex_rpms
+  # Remove older rpms which do not match this version
+  find . ! -name "*${VERSION_EXTENSION}.noarch.rpm" -type f -exec rm -f {} +
+  # Download RPM only if changed on server
+  for rpm in $RPM_LIST; do
+    wget -N ${RPM_INSTALL_PATH}/${rpm}
+  done
   if ! sudo yum install -y $RPM_LIST; then
     echo "Unable to install new RPMs: $RPM_LIST"
     exit 1
   fi
+  popd
 fi
 
 # TODO: Uncomment these lines to verify SHA512SUMs once the sums are
diff --git a/jjb/apex/apex-project-jobs.yml b/jjb/apex/apex-project-jobs.yml
new file mode 100644 (file)
index 0000000..973ad91
--- /dev/null
@@ -0,0 +1,127 @@
+---
+- project:
+    name: 'apex-project-jobs'
+    project: 'apex'
+
+    stream:
+      - master: &master
+          branch: 'master'
+          gs-pathname: ''
+          concurrent-builds: 3
+          disabled: false
+
+      - danube: &danube
+          branch: 'stable/danube'
+          gs-pathname: '/danube'
+          concurrent-builds: 1
+          disabled: true
+
+    jobs:
+      - 'apex-build-{stream}'
+      - 'apex-verify-iso-{stream}'
+
+# Build phase
+- job-template:
+    name: 'apex-build-{stream}'
+
+    # Job template for builds
+    #
+    # Required Variables:
+    #     stream:    branch with - in place of / (eg. stable)
+    #     branch:    branch (eg. stable)
+    node: 'apex-build-{stream}'
+
+    disabled: false
+
+    concurrent: true
+
+    parameters:
+      - '{project}-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - apex-parameter:
+          gs-pathname: '{gs-pathname}'
+
+    scm:
+      - git-scm-gerrit
+
+    wrappers:
+      - timeout:
+          timeout: 150
+          fail: true
+
+    properties:
+      - logrotate-default
+      - throttle:
+          max-per-node: '{concurrent-builds}'
+          max-total: 10
+          option: 'project'
+      - build-blocker:
+          use-build-blocker: true
+          block-level: 'NODE'
+          blocking-jobs:
+            - 'apex-verify-iso-{stream}'
+
+    builders:
+      - 'apex-build'
+      - inject:
+          properties-content: ARTIFACT_TYPE=rpm
+      - 'apex-upload-artifact'
+
+# ISO verify job
+- job-template:
+    name: 'apex-verify-iso-{stream}'
+
+    # Job template for builds
+    #
+    # Required Variables:
+    #     stream:    branch with - in place of / (eg. stable)
+    #     branch:    branch (eg. stable)
+    node: 'apex-virtual-{stream}'
+
+    disabled: false
+
+    concurrent: true
+
+    parameters:
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - apex-parameter:
+          gs-pathname: '{gs-pathname}'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: "Used for overriding the GIT URL coming from parameters macro."
+
+    scm:
+      - git-scm
+
+    properties:
+      - logrotate-default
+      - throttle:
+          max-per-node: 1
+          max-total: 10
+          option: 'project'
+
+    builders:
+      - 'apex-iso-verify'
+      - inject:
+          properties-content: ARTIFACT_TYPE=iso
+      - 'apex-upload-artifact'
+
+########################
+# builder macros
+########################
+- builder:
+    name: 'apex-build'
+    builders:
+      - shell:
+          !include-raw: ./apex-build.sh
+
+- builder:
+    name: 'apex-iso-verify'
+    builders:
+      - shell:
+          !include-raw: ./apex-iso-verify.sh
index 12cb862..3112c9d 100755 (executable)
@@ -8,10 +8,24 @@ echo "--------------------------------------------------------------------------
 echo
 
 
-pushd ci/ > /dev/null
-sudo BASE="${WORKSPACE}/build" LIB="${WORKSPACE}/lib" ./clean.sh
-./test.sh
-popd
+pushd build/ > /dev/null
+for pkg in yamllint rpmlint iproute epel-release python34-devel python34-nose python34-PyYAML python-pep8 python34-mock python34-pip; do
+  if ! rpm -q ${pkg} > /dev/null; then
+    if ! sudo yum install -y ${pkg}; then
+      echo "Failed to install ${pkg} package..."
+      exit 1
+    fi
+  fi
+done
+
+# Make sure coverage is installed
+if ! python3 -c "import coverage" &> /dev/null; then sudo pip3 install coverage; fi
+
+make rpmlint
+make python-pep8-check
+make yamllint
+make python-tests
+popd > /dev/null
 
 echo "--------------------------------------------------------"
 echo "Unit Tests Done!"
index f53451d..4037d25 100755 (executable)
@@ -126,15 +126,13 @@ elif [ "$ARTIFACT_TYPE" == 'rpm' ]; then
     RPM_INSTALL_PATH=$BUILD_DIRECTORY/noarch
     RPM_LIST=$RPM_INSTALL_PATH/$(basename $OPNFV_RPM_URL)
     VERSION_EXTENSION=$(echo $(basename $OPNFV_RPM_URL) | sed 's/opnfv-apex-//')
-    for pkg in common undercloud onos; do
-      RPM_LIST+=" ${RPM_INSTALL_PATH}/opnfv-apex-${pkg}-${VERSION_EXTENSION}"
-    done
+    RPM_LIST+=" ${RPM_INSTALL_PATH}/opnfv-apex-undercloud-${VERSION_EXTENSION}"
+    RPM_LIST+=" ${RPM_INSTALL_PATH}/python34-opnfv-apex-${VERSION_EXTENSION}"
     SRPM_INSTALL_PATH=$BUILD_DIRECTORY
     SRPM_LIST=$SRPM_INSTALL_PATH/$(basename $OPNFV_SRPM_URL)
     VERSION_EXTENSION=$(echo $(basename $OPNFV_SRPM_URL) | sed 's/opnfv-apex-//')
-    for pkg in common undercloud onos; do
-      SRPM_LIST+=" ${SRPM_INSTALL_PATH}/opnfv-apex-${pkg}-${VERSION_EXTENSION}"
-    done
+    SRPM_LIST+=" ${SRPM_INSTALL_PATH}/opnfv-apex-undercloud-${VERSION_EXTENSION}"
+    SRPM_LIST+=" ${SRPM_INSTALL_PATH}/python34-opnfv-apex-${VERSION_EXTENSION}"
 
     if [[ -n "$SIGN_ARTIFACT" && "$SIGN_ARTIFACT" == "true" ]]; then
       signrpm
diff --git a/jjb/apex/apex-workspace-cleanup.sh b/jjb/apex/apex-workspace-cleanup.sh
deleted file mode 100755 (executable)
index d2f71a5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-set -o errexit
-set -o nounset
-set -o pipefail
-
-# delete everything that is in $WORKSPACE
-sudo /bin/rm -rf $WORKSPACE
index a395cf2..c71bee1 100644 (file)
         - 'apex-verify-gate-{stream}'
         - 'apex-verify-unit-tests-{stream}'
         - 'apex-runner-cperf-{stream}'
-        - 'apex-build-{stream}'
         - 'apex-deploy-{platform}-{stream}'
         - 'apex-daily-master'
         - 'apex-daily-danube'
         - 'apex-csit-promote-daily-{stream}'
         - 'apex-fdio-promote-daily-{stream}'
-        - 'apex-verify-iso-{stream}'
-        - 'apex-run-deploy-test-baremetal-{stream}'
+        - 'apex-{scenario}-baremetal-{scenario_stream}'
+        - 'apex-testsuite-{scenario}-baremetal-{scenario_stream}'
         - 'apex-upload-snapshot'
         - 'apex-create-snapshot'
+        - 'apex-flex-daily-os-nosdn-nofeature-ha-{stream}'
     # stream:    branch with - in place of / (eg. stable-arno)
     # branch:    branch (eg. stable/arno)
     stream:
-        - master:
+        - master: &master
             branch: 'master'
             gs-pathname: ''
             build-slave: 'apex-build-master'
             virtual-slave: 'apex-virtual-master'
             baremetal-slave: 'apex-baremetal-master'
             verify-scenario: 'os-odl-nofeature-ha'
-            concurrent-builds: 3
+            scenario_stream: 'master'
 
-        - danube:
+        - danube: &danube
             branch: 'stable/danube'
             gs-pathname: '/danube'
             build-slave: 'apex-build-danube'
             virtual-slave: 'apex-virtual-danube'
             baremetal-slave: 'apex-baremetal-danube'
             verify-scenario: 'os-odl_l3-nofeature-ha'
-            concurrent-builds: 1
-            disabled: false
+            scenario_stream: 'danube'
+            disabled: true
+
+    scenario:
+        - 'os-nosdn-nofeature-noha':
+              <<: *danube
+        - 'os-nosdn-nofeature-ha':
+              <<: *danube
+        - 'os-nosdn-nofeature-ha-ipv6':
+              <<: *danube
+        - 'os-nosdn-ovs-noha':
+              <<: *danube
+        - 'os-nosdn-ovs-ha':
+              <<: *danube
+        - 'os-nosdn-fdio-noha':
+              <<: *danube
+        - 'os-nosdn-fdio-ha':
+              <<: *danube
+        - 'os-nosdn-kvm-ha':
+              <<: *danube
+        - 'os-nosdn-kvm-noha':
+              <<: *danube
+        - 'os-odl_l2-fdio-noha':
+              <<: *danube
+        - 'os-odl_l2-fdio-ha':
+              <<: *danube
+        - 'os-odl_netvirt-fdio-noha':
+              <<: *danube
+        - 'os-odl_l2-sfc-noha':
+              <<: *danube
+        - 'os-odl_l3-nofeature-noha':
+              <<: *danube
+        - 'os-odl_l3-nofeature-ha':
+              <<: *danube
+        - 'os-odl_l3-ovs-noha':
+              <<: *danube
+        - 'os-odl_l3-ovs-ha':
+              <<: *danube
+        - 'os-odl-bgpvpn-ha':
+              <<: *danube
+        - 'os-odl-gluon-noha':
+              <<: *danube
+        - 'os-odl_l3-fdio-noha':
+              <<: *danube
+        - 'os-odl_l3-fdio-ha':
+              <<: *danube
+        - 'os-odl_l3-fdio_dvr-noha':
+              <<: *danube
+        - 'os-odl_l3-fdio_dvr-ha':
+              <<: *danube
+        - 'os-odl_l3-csit-noha':
+              <<: *danube
+        - 'os-onos-nofeature-ha':
+              <<: *danube
+        - 'os-ovn-nofeature-noha':
+              <<: *danube
+        - 'os-nosdn-nofeature-noha':
+              <<: *master
+        - 'os-nosdn-nofeature-ha':
+              <<: *master
+        - 'os-odl-nofeature-ha':
+              <<: *master
+        - 'os-odl-nofeature-noha':
+              <<: *master
+        - 'os-odl-bgpvpn-ha':
+              <<: *master
+        - 'os-ovn-nofeature-noha':
+              <<: *master
+        - 'os-nosdn-fdio-noha':
+              <<: *master
+        - 'os-nosdn-fdio-ha':
+              <<: *master
+        - 'os-odl-fdio-noha':
+              <<: *master
+        - 'os-odl-fdio-ha':
+              <<: *master
+        - 'os-nosdn-bar-ha':
+              <<: *master
+        - 'os-nosdn-bar-noha':
+              <<: *master
+        - 'os-nosdn-nofeature-ha-ipv6':
+              <<: *master
+        - 'os-nosdn-ovs_dpdk-noha':
+              <<: *master
+        - 'os-nosdn-ovs_dpdk-ha':
+              <<: *master
+        - 'os-nosdn-kvm_ovs_dpdk-noha':
+              <<: *master
+        - 'os-nosdn-kvm_ovs_dpdk-ha':
+              <<: *master
+        - 'os-odl-sfc-noha':
+              <<: *master
+        - 'os-odl-sfc-ha':
+              <<: *master
+        - 'os-odl-fdio-dvr-noha':
+              <<: *master
+        - 'os-odl-fdio-dvr-ha':
+              <<: *master
 
     platform:
          - 'baremetal'
                 branches:
                   - branch-compare-type: 'ANT'
                     branch-pattern: '**/{branch}'
+                disable-strict-forbidden-file-verification: 'false'
                 file-paths:
                   - compare-type: ANT
-                    pattern: 'tests/**'
+                    pattern: 'apex/tests/**'
+                forbidden-file-paths:
+                  - compare-type: ANT
+                    pattern: '*'
+                  - compare-type: ANT
+                    pattern: 'apex/*'
+                  - compare-type: ANT
+                    pattern: 'build/**'
+                  - compare-type: ANT
+                    pattern: 'lib/**'
+                  - compare-type: ANT
+                    pattern: 'config/**'
+                  - compare-type: ANT
+                    pattern: 'apex/build/**'
+                  - compare-type: ANT
+                    pattern: 'apex/common/**'
+                  - compare-type: ANT
+                    pattern: 'apex/inventory/**'
+                  - compare-type: ANT
+                    pattern: 'apex/network/**'
+                  - compare-type: ANT
+                    pattern: 'apex/overcloud/**'
+                  - compare-type: ANT
+                    pattern: 'apex/settings/**'
+                  - compare-type: ANT
+                    pattern: 'apex/undercloud/**'
+                  - compare-type: ANT
+                    pattern: 'apex/virtual/**'
     properties:
         - logrotate-default
         - throttle:
                 branches:
                   - branch-compare-type: 'ANT'
                     branch-pattern: '**/{branch}'
+                disable-strict-forbidden-file-verification: 'true'
                 file-paths:
                   - compare-type: ANT
-                    pattern: 'ci/**'
+                    pattern: '*'
+                  - compare-type: ANT
+                    pattern: 'apex/*'
                   - compare-type: ANT
                     pattern: 'build/**'
                   - compare-type: ANT
                     pattern: 'lib/**'
                   - compare-type: ANT
                     pattern: 'config/**'
+                  - compare-type: ANT
+                    pattern: 'apex/build/**'
+                  - compare-type: ANT
+                    pattern: 'apex/common/**'
+                  - compare-type: ANT
+                    pattern: 'apex/inventory/**'
+                  - compare-type: ANT
+                    pattern: 'apex/network/**'
+                  - compare-type: ANT
+                    pattern: 'apex/overcloud/**'
+                  - compare-type: ANT
+                    pattern: 'apex/settings/**'
+                  - compare-type: ANT
+                    pattern: 'apex/undercloud/**'
+                  - compare-type: ANT
+                    pattern: 'apex/virtual/**'
+                forbidden-file-paths:
+                  - compare-type: ANT
+                    pattern: 'apex/tests/**'
+                  - compare-type: ANT
+                    pattern: 'docs/**'
 
     properties:
         - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            block-level: 'NODE'
+            blocking-jobs:
+                - 'apex-verify.*'
         - throttle:
-            max-per-node: 3
+            max-per-node: 1
             max-total: 10
             option: 'project'
 
                     pattern: 'lib/**'
                   - compare-type: ANT
                     pattern: 'config/**'
+                  - compare-type: ANT
+                    pattern: 'apex/**'
 
     properties:
         - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            block-level: 'NODE'
+            blocking-jobs:
+                - 'apex-verify.*'
         - throttle:
-            max-per-node: 3
+            max-per-node: 1
             max-total: 10
             option: 'project'
 
                   kill-phase-on: FAILURE
                   abort-all-job: true
                   git-revision: true
+        - shell: |
+            echo DEPLOY_SCENARIO=$(echo $GERRIT_EVENT_COMMENT_TEXT | grep start-gate-scenario | grep -Eo 'os-.*') > detected_scenario
+        - inject:
+           properties-file: detected_scenario
         - multijob:
             name: functest-smoke
             condition: SUCCESSFUL
               - name: 'functest-apex-virtual-suite-{stream}'
                 current-parameters: false
                 predefined-parameters: |
-                  DEPLOY_SCENARIO={verify-scenario}
+                  DEPLOY_SCENARIO=$DEPLOY_SCENARIO
                   FUNCTEST_SUITE_NAME=healthcheck
                   GERRIT_BRANCH=$GERRIT_BRANCH
                   GERRIT_REFSPEC=$GERRIT_REFSPEC
                   abort-all-job: false
                   git-revision: false
 
-# Build phase
-- job-template:
-    name: 'apex-build-{stream}'
-
-    # Job template for builds
-    #
-    # Required Variables:
-    #     stream:    branch with - in place of / (eg. stable)
-    #     branch:    branch (eg. stable)
-    node: '{build-slave}'
-
-    disabled: false
-
-    concurrent: true
-
-    parameters:
-        - '{project}-defaults'
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - apex-parameter:
-            gs-pathname: '{gs-pathname}'
-
-    scm:
-        - git-scm-gerrit
-
-    wrappers:
-        - timeout:
-            timeout: 150
-            fail: true
-
-    properties:
-        - logrotate-default
-        - throttle:
-            max-per-node: {concurrent-builds}
-            max-total: 10
-            option: 'project'
-        - build-blocker:
-            use-build-blocker: true
-            block-level: 'NODE'
-            blocking-jobs:
-                - 'apex-verify-iso-{stream}'
-
-    builders:
-        - 'apex-build'
-        - inject:
-           properties-content: ARTIFACT_TYPE=rpm
-        - 'apex-upload-artifact'
-
-# ISO verify job
-- job-template:
-    name: 'apex-verify-iso-{stream}'
-
-    # Job template for builds
-    #
-    # Required Variables:
-    #     stream:    branch with - in place of / (eg. stable)
-    #     branch:    branch (eg. stable)
-    node: '{virtual-slave}'
-
-    disabled: false
-
-    concurrent: true
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - apex-parameter:
-            gs-pathname: '{gs-pathname}'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: "Used for overriding the GIT URL coming from parameters macro."
-
-    scm:
-        - git-scm
-
-    properties:
-        - logrotate-default
-        - throttle:
-            max-per-node: 1
-            max-total: 10
-            option: 'project'
-
-    builders:
-        - 'apex-iso-verify'
-        - inject:
-           properties-content: ARTIFACT_TYPE=iso
-        - 'apex-upload-artifact'
-
 # Deploy job
 - job-template:
     name: 'apex-deploy-{platform}-{stream}'
 
-    # Job template for virtual deployment
-    #
-    # Required Variables:
-    #     stream:    branch with - in place of / (eg. stable)
-    #     branch:    branch (eg. stable)
     node: 'apex-{platform}-{stream}'
 
     concurrent: true
 
     disabled: false
-
+    quiet-period: 30
     scm:
         - git-scm-gerrit
 
     wrappers:
         - timeout:
-            timeout: 120
+            timeout: 140
             fail: true
 
     parameters:
+        - '{project}-{platform}-{stream}-defaults'
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
                 - 'apex-deploy.*'
                 - 'functest.*'
                 - 'yardstick.*'
+                - 'dovetail.*'
+                - 'storperf.*'
         - throttle:
             max-per-node: 1
             max-total: 10
             description: "Deployed on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
         - 'apex-download-artifact'
         - 'apex-deploy'
-        - 'apex-workspace-cleanup'
+        - 'clean-workspace'
 
 
 # Baremetal Deploy and Test
 - job-template:
-    name: 'apex-run-deploy-test-baremetal-{stream}'
+    name: 'apex-{scenario}-baremetal-{scenario_stream}'
 
-    # Job template for daily build
-    #
-    # Required Variables:
-    #     stream:    branch with - in place of / (eg. stable)
-    #     branch:    branch (eg. stable)
     project-type: 'multijob'
 
     disabled: false
 
     parameters:
         - '{project}-defaults'
-        - '{project}-baremetal-{stream}-defaults'
+        - '{project}-baremetal-{scenario_stream}-defaults'
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
             gs-pathname: '{gs-pathname}'
         - string:
             name: DEPLOY_SCENARIO
-            default: '{verify-scenario}'
+            default: '{scenario}'
             description: "Scenario to deploy with."
     properties:
         - logrotate-default
                 - 'apex-runner.*'
                 - 'apex-.*-promote.*'
                 - 'apex-run.*'
+                - 'apex-.+-baremetal-.+'
+        - throttle:
+            max-per-node: 1
+            max-total: 10
+            option: 'project'
     builders:
         - description-setter:
             description: "Deployed on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
         - multijob:
             name: 'Baremetal Deploy'
-            condition: ALWAYS
+            condition: SUCCESSFUL
             projects:
-                - name: 'apex-deploy-baremetal-{stream}'
+                - name: 'apex-deploy-baremetal-{scenario_stream}'
                   node-parameters: true
                   current-parameters: true
                   predefined-parameters: |
                   kill-phase-on: FAILURE
                   abort-all-job: true
                   git-revision: false
+        - multijob:
+            name: 'OPNFV Test Suite'
+            projects:
+                - name: 'apex-testsuite-{scenario}-baremetal-{scenario_stream}'
+                  node-parameters: true
+                  current-parameters: false
+                  predefined-parameters:
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+    publishers:
+        - groovy-postbuild:
+            script:
+                !include-raw-escape: ./update-build-result.groovy
+
+# Baremetal test job
+- job-template:
+    name: 'apex-testsuite-{scenario}-baremetal-{scenario_stream}'
+
+    project-type: 'multijob'
+
+    disabled: false
+
+    parameters:
+        - '{project}-defaults'
+        - '{project}-baremetal-{scenario_stream}-defaults'
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - apex-parameter:
+            gs-pathname: '{gs-pathname}'
+        - string:
+            name: DEPLOY_SCENARIO
+            default: '{scenario}'
+            description: "Scenario to deploy with."
+    properties:
+        - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            block-level: 'NODE'
+            blocking-jobs:
+                - 'apex-verify.*'
+                - 'apex-runner.*'
+                - 'apex-.*-promote.*'
+                - 'apex-run.*'
+                - 'apex-testsuite-.+-baremetal-.+'
+        - throttle:
+            max-per-node: 1
+            max-total: 10
+            option: 'project'
+    builders:
+        - description-setter:
+            description: "Testing on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
         - multijob:
             name: Functest
             condition: ALWAYS
             projects:
-                - name: 'functest-apex-baremetal-daily-{stream}'
+                - name: 'functest-apex-baremetal-daily-{scenario_stream}'
                   node-parameters: true
                   current-parameters: false
                   predefined-parameters:
             name: Yardstick
             condition: ALWAYS
             projects:
-                - name: 'yardstick-apex-baremetal-daily-{stream}'
+                - name: 'yardstick-apex-baremetal-daily-{scenario_stream}'
                   node-parameters: true
                   current-parameters: false
                   predefined-parameters:
                   kill-phase-on: NEVER
                   abort-all-job: false
                   git-revision: false
+        - multijob:
+            name: Dovetail
+            condition: ALWAYS
+            projects:
+                - name: 'dovetail-apex-baremetal-proposed_tests-{scenario_stream}'
+                  node-parameters: true
+                  current-parameters: false
+                  predefined-parameters:
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  kill-phase-on: NEVER
+                  enable-condition: "def m = '$DEPLOY_SCENARIO' ==~ /os-(nosdn-nofeature|nosdn-kvm|odl_l3-fdio)-ha/"
+                  abort-all-job: false
+                  git-revision: false
+        - multijob:
+            name: StorPerf
+            condition: ALWAYS
+            projects:
+                - name: 'storperf-apex-baremetal-daily-{scenario_stream}'
+                  node-parameters: true
+                  current-parameters: false
+                  predefined-parameters:
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  enable-condition: "def m = '$DEPLOY_SCENARIO' ==~ /os-nosdn-nofeature-ha/"
+                  kill-phase-on: NEVER
+                  abort-all-job: false
+                  git-revision: false
+# Build status is always success due conditional plugin prefetching
+# build status before multijob phases execute
+#        - conditional-step:
+#            condition-kind: current-status
+#            condition-worst: SUCCESS
+#            condtion-best: SUCCESS
+#            on-evaluation-failure: mark-unstable
+#            steps:
+#                - shell: 'echo "Tests Passed"'
 
 
 # danube Daily
             condition: SUCCESSFUL
             projects:
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-nosdn-nofeature-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-nofeature-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-nosdn-nofeature-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-nofeature-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-nosdn-nofeature-ha-ipv6-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-nofeature-ha-ipv6
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-nosdn-ovs-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-ovs-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-nosdn-ovs-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-ovs-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-nosdn-fdio-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-fdio-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-nosdn-fdio-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-fdio-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-nosdn-kvm-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-kvm-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-nosdn-kvm-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-kvm-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l2-fdio-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l2-fdio-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l2-fdio-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l2-fdio-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_netvirt-fdio-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_netvirt-fdio-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l2-sfc-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l2-sfc-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l3-nofeature-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-nofeature-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l3-nofeature-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-nofeature-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l3-ovs-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-ovs-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l3-ovs-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-ovs-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl-bgpvpn-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl-bgpvpn-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl-gluon-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl-gluon-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l3-fdio-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-fdio-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l3-fdio-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-fdio-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l3-fdio_dvr-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-fdio_dvr-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l3-fdio_dvr-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-fdio_dvr-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-odl_l3-csit-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl_l3-csit-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-onos-nofeature-ha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-onos-nofeature-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-danube'
+                - name: 'apex-os-ovn-nofeature-noha-baremetal-danube'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-ovn-nofeature-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
             condition: SUCCESSFUL
             projects:
 
-                - name: 'apex-run-deploy-test-baremetal-master'
+                - name: 'apex-os-nosdn-nofeature-noha-baremetal-master'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-nofeature-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-master'
+                - name: 'apex-os-nosdn-nofeature-ha-baremetal-master'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-nofeature-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-master'
+                - name: 'apex-os-odl-nofeature-ha-baremetal-master'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl-nofeature-ha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                   git-revision: false
 
-                - name: 'apex-run-deploy-test-baremetal-master'
+                - name: 'apex-os-odl-nofeature-noha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-odl-bgpvpn-ha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-ovn-nofeature-noha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-nosdn-fdio-noha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-nosdn-fdio-ha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-odl-fdio-noha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-odl-fdio-ha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-nosdn-bar-ha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-nosdn-bar-noha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-nosdn-nofeature-ha-ipv6-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-nosdn-ovs_dpdk-noha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-nosdn-ovs_dpdk-ha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-nosdn-kvm_ovs_dpdk-noha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-nosdn-kvm_ovs_dpdk-ha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-odl-sfc-noha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-odl-sfc-ha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-odl-fdio-dvr-noha-baremetal-master'
+                  node-parameters: false
+                  current-parameters: false
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+                - name: 'apex-os-odl-fdio-dvr-ha-baremetal-master'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO=os-odl-nofeature-noha
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                 abort-all-job: true
                 git-revision: false
 
+# Flex job
+- job-template:
+    name: 'apex-flex-daily-os-nosdn-nofeature-ha-{stream}'
+
+    project-type: 'multijob'
+
+    disabled: false
+
+    node: 'flex-pod2'
+
+    scm:
+        - git-scm
+    triggers:
+        - 'apex-{stream}'
+    parameters:
+        - '{project}-defaults'
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - apex-parameter:
+            gs-pathname: '{gs-pathname}'
+        - string:
+            name: DEPLOY_SCENARIO
+            default: 'os-nosdn-nofeature-ha'
+            description: "Scenario to deploy with."
+        - string:
+            name: GIT_BASE
+            default: https://gerrit.opnfv.org/gerrit/$PROJECT
+            description: 'Git URL to use on this Jenkins Slave'
+        - string:
+            name: SSH_KEY
+            default: /root/.ssh/id_rsa
+            description: 'SSH key to use for Apex'
+    properties:
+        - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            block-level: 'NODE'
+            blocking-jobs:
+                - 'apex-verify.*'
+                - 'apex-runner.*'
+                - 'apex-.*-promote.*'
+                - 'apex-run.*'
+                - 'apex-.+-baremetal-.+'
+        - throttle:
+            max-per-node: 1
+            max-total: 10
+            option: 'project'
+    builders:
+        - description-setter:
+            description: "Deployed on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
+        - multijob:
+            name: 'Baremetal Deploy'
+            condition: SUCCESSFUL
+            projects:
+                - name: 'apex-deploy-baremetal-{stream}'
+                  node-parameters: true
+                  current-parameters: true
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                    GERRIT_BRANCH=$GERRIT_BRANCH
+                    GERRIT_REFSPEC=
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  kill-phase-on: FAILURE
+                  abort-all-job: true
+                  git-revision: false
+        - multijob:
+            name: Yardstick
+            condition: ALWAYS
+            projects:
+                - name: 'yardstick-apex-baremetal-daily-{stream}'
+                  node-parameters: true
+                  current-parameters: false
+                  predefined-parameters:
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  kill-phase-on: NEVER
+                  abort-all-job: false
+                  git-revision: false
+
 ########################
 # parameter macros
 ########################
         - shell:
             !include-raw: ./apex-unit-test.sh
 
-- builder:
-    name: 'apex-build'
-    builders:
-        - shell:
-            !include-raw: ./apex-build.sh
-
-- builder:
-    name: 'apex-workspace-cleanup'
-    builders:
-        - shell:
-            !include-raw: ./apex-workspace-cleanup.sh
-
-- builder:
-    name: 'apex-iso-verify'
-    builders:
-        - shell:
-            !include-raw: ./apex-iso-verify.sh
-
-
 - builder:
     name: 'apex-upload-artifact'
     builders:
 - trigger:
     name: 'apex-master'
     triggers:
-        - timed: '0 3 1 1 7'
+        - timed: '0 12 * * *'
 - trigger:
     name: 'apex-danube'
     triggers:
-        - timed: '0 12 * * *'
+        - timed: '0 3 1 1 7'
index 752cf28..356c718 100644 (file)
@@ -6,37 +6,45 @@
         - 'apex-verify-gate-{stream}'
         - 'apex-verify-unit-tests-{stream}'
         - 'apex-runner-cperf-{stream}'
-        - 'apex-build-{stream}'
         - 'apex-deploy-{platform}-{stream}'
         - 'apex-daily-master'
         - 'apex-daily-danube'
         - 'apex-csit-promote-daily-{stream}'
         - 'apex-fdio-promote-daily-{stream}'
-        - 'apex-verify-iso-{stream}'
-        - 'apex-run-deploy-test-baremetal-{stream}'
+        - 'apex-{scenario}-baremetal-{scenario_stream}'
+        - 'apex-testsuite-{scenario}-baremetal-{scenario_stream}'
         - 'apex-upload-snapshot'
         - 'apex-create-snapshot'
+        - 'apex-flex-daily-os-nosdn-nofeature-ha-{stream}'
     # stream:    branch with - in place of / (eg. stable-arno)
     # branch:    branch (eg. stable/arno)
     stream:
-        - master:
+        - master: &master
             branch: 'master'
             gs-pathname: ''
             build-slave: 'apex-build-master'
             virtual-slave: 'apex-virtual-master'
             baremetal-slave: 'apex-baremetal-master'
             verify-scenario: 'os-odl-nofeature-ha'
-            concurrent-builds: 3
+            scenario_stream: 'master'
 
-        - danube:
+        - danube: &danube
             branch: 'stable/danube'
             gs-pathname: '/danube'
             build-slave: 'apex-build-danube'
             virtual-slave: 'apex-virtual-danube'
             baremetal-slave: 'apex-baremetal-danube'
             verify-scenario: 'os-odl_l3-nofeature-ha'
-            concurrent-builds: 1
-            disabled: false
+            scenario_stream: 'danube'
+            disabled: true
+
+    scenario:
+        {%- for stream in scenarios %}
+        {%- for scenario in scenarios[stream] %}
+        - '{{scenario}}':
+              <<: *{{stream}}
+        {%- endfor %}
+        {%- endfor %}
 
     platform:
          - 'baremetal'
                 branches:
                   - branch-compare-type: 'ANT'
                     branch-pattern: '**/{branch}'
+                disable-strict-forbidden-file-verification: 'false'
                 file-paths:
                   - compare-type: ANT
-                    pattern: 'tests/**'
+                    pattern: 'apex/tests/**'
+                forbidden-file-paths:
+                  - compare-type: ANT
+                    pattern: '*'
+                  - compare-type: ANT
+                    pattern: 'apex/*'
+                  - compare-type: ANT
+                    pattern: 'build/**'
+                  - compare-type: ANT
+                    pattern: 'lib/**'
+                  - compare-type: ANT
+                    pattern: 'config/**'
+                  - compare-type: ANT
+                    pattern: 'apex/build/**'
+                  - compare-type: ANT
+                    pattern: 'apex/common/**'
+                  - compare-type: ANT
+                    pattern: 'apex/inventory/**'
+                  - compare-type: ANT
+                    pattern: 'apex/network/**'
+                  - compare-type: ANT
+                    pattern: 'apex/overcloud/**'
+                  - compare-type: ANT
+                    pattern: 'apex/settings/**'
+                  - compare-type: ANT
+                    pattern: 'apex/undercloud/**'
+                  - compare-type: ANT
+                    pattern: 'apex/virtual/**'
     properties:
         - logrotate-default
         - throttle:
                 branches:
                   - branch-compare-type: 'ANT'
                     branch-pattern: '**/{branch}'
+                disable-strict-forbidden-file-verification: 'true'
                 file-paths:
                   - compare-type: ANT
-                    pattern: 'ci/**'
+                    pattern: '*'
+                  - compare-type: ANT
+                    pattern: 'apex/*'
                   - compare-type: ANT
                     pattern: 'build/**'
                   - compare-type: ANT
                     pattern: 'lib/**'
                   - compare-type: ANT
                     pattern: 'config/**'
+                  - compare-type: ANT
+                    pattern: 'apex/build/**'
+                  - compare-type: ANT
+                    pattern: 'apex/common/**'
+                  - compare-type: ANT
+                    pattern: 'apex/inventory/**'
+                  - compare-type: ANT
+                    pattern: 'apex/network/**'
+                  - compare-type: ANT
+                    pattern: 'apex/overcloud/**'
+                  - compare-type: ANT
+                    pattern: 'apex/settings/**'
+                  - compare-type: ANT
+                    pattern: 'apex/undercloud/**'
+                  - compare-type: ANT
+                    pattern: 'apex/virtual/**'
+                forbidden-file-paths:
+                  - compare-type: ANT
+                    pattern: 'apex/tests/**'
+                  - compare-type: ANT
+                    pattern: 'docs/**'
 
     properties:
         - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            block-level: 'NODE'
+            blocking-jobs:
+                - 'apex-verify.*'
         - throttle:
-            max-per-node: 3
+            max-per-node: 1
             max-total: 10
             option: 'project'
 
                     pattern: 'lib/**'
                   - compare-type: ANT
                     pattern: 'config/**'
+                  - compare-type: ANT
+                    pattern: 'apex/**'
 
     properties:
         - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            block-level: 'NODE'
+            blocking-jobs:
+                - 'apex-verify.*'
         - throttle:
-            max-per-node: 3
+            max-per-node: 1
             max-total: 10
             option: 'project'
 
                   kill-phase-on: FAILURE
                   abort-all-job: true
                   git-revision: true
+        - shell: |
+            echo DEPLOY_SCENARIO=$(echo $GERRIT_EVENT_COMMENT_TEXT | grep start-gate-scenario | grep -Eo 'os-.*') > detected_scenario
+        - inject:
+           properties-file: detected_scenario
         - multijob:
             name: functest-smoke
             condition: SUCCESSFUL
               - name: 'functest-apex-virtual-suite-{stream}'
                 current-parameters: false
                 predefined-parameters: |
-                  DEPLOY_SCENARIO={verify-scenario}
+                  DEPLOY_SCENARIO=$DEPLOY_SCENARIO
                   FUNCTEST_SUITE_NAME=healthcheck
                   GERRIT_BRANCH=$GERRIT_BRANCH
                   GERRIT_REFSPEC=$GERRIT_REFSPEC
                   abort-all-job: false
                   git-revision: false
 
-# Build phase
-- job-template:
-    name: 'apex-build-{stream}'
-
-    # Job template for builds
-    #
-    # Required Variables:
-    #     stream:    branch with - in place of / (eg. stable)
-    #     branch:    branch (eg. stable)
-    node: '{build-slave}'
-
-    disabled: false
-
-    concurrent: true
-
-    parameters:
-        - '{project}-defaults'
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - apex-parameter:
-            gs-pathname: '{gs-pathname}'
-
-    scm:
-        - git-scm-gerrit
-
-    wrappers:
-        - timeout:
-            timeout: 150
-            fail: true
-
-    properties:
-        - logrotate-default
-        - throttle:
-            max-per-node: {concurrent-builds}
-            max-total: 10
-            option: 'project'
-        - build-blocker:
-            use-build-blocker: true
-            block-level: 'NODE'
-            blocking-jobs:
-                - 'apex-verify-iso-{stream}'
-
-    builders:
-        - 'apex-build'
-        - inject:
-           properties-content: ARTIFACT_TYPE=rpm
-        - 'apex-upload-artifact'
-
-# ISO verify job
-- job-template:
-    name: 'apex-verify-iso-{stream}'
-
-    # Job template for builds
-    #
-    # Required Variables:
-    #     stream:    branch with - in place of / (eg. stable)
-    #     branch:    branch (eg. stable)
-    node: '{virtual-slave}'
-
-    disabled: false
-
-    concurrent: true
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - apex-parameter:
-            gs-pathname: '{gs-pathname}'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: "Used for overriding the GIT URL coming from parameters macro."
-
-    scm:
-        - git-scm
-
-    properties:
-        - logrotate-default
-        - throttle:
-            max-per-node: 1
-            max-total: 10
-            option: 'project'
-
-    builders:
-        - 'apex-iso-verify'
-        - inject:
-           properties-content: ARTIFACT_TYPE=iso
-        - 'apex-upload-artifact'
-
 # Deploy job
 - job-template:
     name: 'apex-deploy-{platform}-{stream}'
 
-    # Job template for virtual deployment
-    #
-    # Required Variables:
-    #     stream:    branch with - in place of / (eg. stable)
-    #     branch:    branch (eg. stable)
     node: 'apex-{platform}-{stream}'
 
     concurrent: true
 
     disabled: false
-
+    quiet-period: 30
     scm:
         - git-scm-gerrit
 
     wrappers:
         - timeout:
-            timeout: 120
+            timeout: 140
             fail: true
 
     parameters:
+        - '{project}-{platform}-{stream}-defaults'
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
                 - 'apex-deploy.*'
                 - 'functest.*'
                 - 'yardstick.*'
+                - 'dovetail.*'
+                - 'storperf.*'
         - throttle:
             max-per-node: 1
             max-total: 10
             description: "Deployed on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
         - 'apex-download-artifact'
         - 'apex-deploy'
-        - 'apex-workspace-cleanup'
+        - 'clean-workspace'
 
 
 # Baremetal Deploy and Test
 - job-template:
-    name: 'apex-run-deploy-test-baremetal-{stream}'
+    name: 'apex-{scenario}-baremetal-{scenario_stream}'
 
-    # Job template for daily build
-    #
-    # Required Variables:
-    #     stream:    branch with - in place of / (eg. stable)
-    #     branch:    branch (eg. stable)
     project-type: 'multijob'
 
     disabled: false
 
     parameters:
         - '{project}-defaults'
-        - '{project}-baremetal-{stream}-defaults'
+        - '{project}-baremetal-{scenario_stream}-defaults'
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
             gs-pathname: '{gs-pathname}'
         - string:
             name: DEPLOY_SCENARIO
-            default: '{verify-scenario}'
+            default: '{scenario}'
             description: "Scenario to deploy with."
     properties:
         - logrotate-default
                 - 'apex-runner.*'
                 - 'apex-.*-promote.*'
                 - 'apex-run.*'
+                - 'apex-.+-baremetal-.+'
+        - throttle:
+            max-per-node: 1
+            max-total: 10
+            option: 'project'
     builders:
         - description-setter:
             description: "Deployed on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
         - multijob:
             name: 'Baremetal Deploy'
-            condition: ALWAYS
+            condition: SUCCESSFUL
             projects:
-                - name: 'apex-deploy-baremetal-{stream}'
+                - name: 'apex-deploy-baremetal-{scenario_stream}'
                   node-parameters: true
                   current-parameters: true
                   predefined-parameters: |
                   kill-phase-on: FAILURE
                   abort-all-job: true
                   git-revision: false
+        - multijob:
+            name: 'OPNFV Test Suite'
+            projects:
+                - name: 'apex-testsuite-{scenario}-baremetal-{scenario_stream}'
+                  node-parameters: true
+                  current-parameters: false
+                  predefined-parameters:
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+                  git-revision: false
+
+    publishers:
+        - groovy-postbuild:
+            script:
+                !include-raw-escape: ./update-build-result.groovy
+
+# Baremetal test job
+- job-template:
+    name: 'apex-testsuite-{scenario}-baremetal-{scenario_stream}'
+
+    project-type: 'multijob'
+
+    disabled: false
+
+    parameters:
+        - '{project}-defaults'
+        - '{project}-baremetal-{scenario_stream}-defaults'
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - apex-parameter:
+            gs-pathname: '{gs-pathname}'
+        - string:
+            name: DEPLOY_SCENARIO
+            default: '{scenario}'
+            description: "Scenario to deploy with."
+    properties:
+        - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            block-level: 'NODE'
+            blocking-jobs:
+                - 'apex-verify.*'
+                - 'apex-runner.*'
+                - 'apex-.*-promote.*'
+                - 'apex-run.*'
+                - 'apex-testsuite-.+-baremetal-.+'
+        - throttle:
+            max-per-node: 1
+            max-total: 10
+            option: 'project'
+    builders:
+        - description-setter:
+            description: "Testing on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
         - multijob:
             name: Functest
             condition: ALWAYS
             projects:
-                - name: 'functest-apex-baremetal-daily-{stream}'
+                - name: 'functest-apex-baremetal-daily-{scenario_stream}'
                   node-parameters: true
                   current-parameters: false
                   predefined-parameters:
             name: Yardstick
             condition: ALWAYS
             projects:
-                - name: 'yardstick-apex-baremetal-daily-{stream}'
+                - name: 'yardstick-apex-baremetal-daily-{scenario_stream}'
+                  node-parameters: true
+                  current-parameters: false
+                  predefined-parameters:
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  kill-phase-on: NEVER
+                  abort-all-job: false
+                  git-revision: false
+        - multijob:
+            name: Dovetail
+            condition: ALWAYS
+            projects:
+                - name: 'dovetail-apex-baremetal-proposed_tests-{scenario_stream}'
+                  node-parameters: true
+                  current-parameters: false
+                  predefined-parameters:
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  kill-phase-on: NEVER
+                  enable-condition: "def m = '$DEPLOY_SCENARIO' ==~ /os-(nosdn-nofeature|nosdn-kvm|odl_l3-fdio)-ha/"
+                  abort-all-job: false
+                  git-revision: false
+        - multijob:
+            name: StorPerf
+            condition: ALWAYS
+            projects:
+                - name: 'storperf-apex-baremetal-daily-{scenario_stream}'
                   node-parameters: true
                   current-parameters: false
                   predefined-parameters:
                     DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  enable-condition: "def m = '$DEPLOY_SCENARIO' ==~ /os-nosdn-nofeature-ha/"
                   kill-phase-on: NEVER
                   abort-all-job: false
                   git-revision: false
+# Build status is always success due conditional plugin prefetching
+# build status before multijob phases execute
+#        - conditional-step:
+#            condition-kind: current-status
+#            condition-worst: SUCCESS
+#            condtion-best: SUCCESS
+#            on-evaluation-failure: mark-unstable
+#            steps:
+#                - shell: 'echo "Tests Passed"'
 
 {% for stream in scenarios %}
 # {{ stream }} Daily
             condition: SUCCESSFUL
             projects:
 {% for scenario in scenarios[stream] %}
-                - name: 'apex-run-deploy-test-baremetal-{{ stream }}'
+                - name: 'apex-{{ scenario }}-baremetal-{{ stream }}'
                   node-parameters: false
                   current-parameters: false
                   predefined-parameters: |
-                    DEPLOY_SCENARIO={{scenario}}
                     OPNFV_CLEAN=yes
                   kill-phase-on: NEVER
                   abort-all-job: true
                 abort-all-job: true
                 git-revision: false
 
+# Flex job
+- job-template:
+    name: 'apex-flex-daily-os-nosdn-nofeature-ha-{stream}'
+
+    project-type: 'multijob'
+
+    disabled: false
+
+    node: 'flex-pod2'
+
+    scm:
+        - git-scm
+    triggers:
+        - 'apex-{stream}'
+    parameters:
+        - '{project}-defaults'
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - apex-parameter:
+            gs-pathname: '{gs-pathname}'
+        - string:
+            name: DEPLOY_SCENARIO
+            default: 'os-nosdn-nofeature-ha'
+            description: "Scenario to deploy with."
+        - string:
+            name: GIT_BASE
+            default: https://gerrit.opnfv.org/gerrit/$PROJECT
+            description: 'Git URL to use on this Jenkins Slave'
+        - string:
+            name: SSH_KEY
+            default: /root/.ssh/id_rsa
+            description: 'SSH key to use for Apex'
+    properties:
+        - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            block-level: 'NODE'
+            blocking-jobs:
+                - 'apex-verify.*'
+                - 'apex-runner.*'
+                - 'apex-.*-promote.*'
+                - 'apex-run.*'
+                - 'apex-.+-baremetal-.+'
+        - throttle:
+            max-per-node: 1
+            max-total: 10
+            option: 'project'
+    builders:
+        - description-setter:
+            description: "Deployed on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
+        - multijob:
+            name: 'Baremetal Deploy'
+            condition: SUCCESSFUL
+            projects:
+                - name: 'apex-deploy-baremetal-{stream}'
+                  node-parameters: true
+                  current-parameters: true
+                  predefined-parameters: |
+                    OPNFV_CLEAN=yes
+                    GERRIT_BRANCH=$GERRIT_BRANCH
+                    GERRIT_REFSPEC=
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  kill-phase-on: FAILURE
+                  abort-all-job: true
+                  git-revision: false
+        - multijob:
+            name: Yardstick
+            condition: ALWAYS
+            projects:
+                - name: 'yardstick-apex-baremetal-daily-{stream}'
+                  node-parameters: true
+                  current-parameters: false
+                  predefined-parameters:
+                    DEPLOY_SCENARIO=$DEPLOY_SCENARIO
+                  kill-phase-on: NEVER
+                  abort-all-job: false
+                  git-revision: false
+
 ########################
 # parameter macros
 ########################
         - shell:
             !include-raw: ./apex-unit-test.sh
 
-- builder:
-    name: 'apex-build'
-    builders:
-        - shell:
-            !include-raw: ./apex-build.sh
-
-- builder:
-    name: 'apex-workspace-cleanup'
-    builders:
-        - shell:
-            !include-raw: ./apex-workspace-cleanup.sh
-
-- builder:
-    name: 'apex-iso-verify'
-    builders:
-        - shell:
-            !include-raw: ./apex-iso-verify.sh
-
-
 - builder:
     name: 'apex-upload-artifact'
     builders:
 - trigger:
     name: 'apex-master'
     triggers:
-        - timed: '0 3 1 1 7'
+        - timed: '0 12 * * *'
 - trigger:
     name: 'apex-danube'
     triggers:
-        - timed: '0 12 * * *'
+        - timed: '0 3 1 1 7'
 
index dc9107a..def4e79 100644 (file)
@@ -3,6 +3,23 @@ master:
   - 'os-nosdn-nofeature-ha'
   - 'os-odl-nofeature-ha'
   - 'os-odl-nofeature-noha'
+  - 'os-odl-bgpvpn-ha'
+  - 'os-ovn-nofeature-noha'
+  - 'os-nosdn-fdio-noha'
+  - 'os-nosdn-fdio-ha'
+  - 'os-odl-fdio-noha'
+  - 'os-odl-fdio-ha'
+  - 'os-nosdn-bar-ha'
+  - 'os-nosdn-bar-noha'
+  - 'os-nosdn-nofeature-ha-ipv6'
+  - 'os-nosdn-ovs_dpdk-noha'
+  - 'os-nosdn-ovs_dpdk-ha'
+  - 'os-nosdn-kvm_ovs_dpdk-noha'
+  - 'os-nosdn-kvm_ovs_dpdk-ha'
+  - 'os-odl-sfc-noha'
+  - 'os-odl-sfc-ha'
+  - 'os-odl-fdio-dvr-noha'
+  - 'os-odl-fdio-dvr-ha'
 danube:
   - 'os-nosdn-nofeature-noha'
   - 'os-nosdn-nofeature-ha'
diff --git a/jjb/apex/update-build-result.groovy b/jjb/apex/update-build-result.groovy
new file mode 100644 (file)
index 0000000..9edca6b
--- /dev/null
@@ -0,0 +1,5 @@
+import hudson.model.*
+if (manager.logContains('^.*apex-deploy-baremetal.*SUCCESS$')
+      && manager.build.@result == hudson.model.Result.FAILURE) {
+    manager.build.@result = hudson.model.Result.UNSTABLE
+}
index 55d8ff9..faa5971 100644 (file)
         branch: '{stream}'
         gs-pathname: ''
         disabled: false
-    danube: &danube
-        stream: danube
+    euphrates: &euphrates
+        stream: euphrates
         branch: 'stable/{stream}'
         gs-pathname: '/{stream}'
-        disabled: false
+        disabled: true
 #--------------------------------
 # POD, INSTALLER, AND BRANCH MAPPING
 #--------------------------------
 # CI POD's
 #--------------------------------
-#        danube
+#        euphrates
 #--------------------------------
     pod:
         - armband-baremetal:
             slave-label: armband-baremetal
             installer: fuel
-            <<: *danube
+            <<: *euphrates
         - armband-virtual:
             slave-label: armband-virtual
             installer: fuel
-            <<: *danube
+            <<: *euphrates
 #--------------------------------
 #        master
 #--------------------------------
             installer: fuel
             <<: *master
 #--------------------------------
-# NONE-CI POD's
-#--------------------------------
-#        danube
-#--------------------------------
-        - arm-pod2:
-            slave-label: arm-pod2
-            installer: fuel
-            <<: *danube
-        - arm-pod3:
-            slave-label: arm-pod3
-            installer: fuel
-            <<: *danube
-        - arm-pod4:
-            slave-label: arm-pod4
-            installer: fuel
-            <<: *danube
-        - arm-virtual1:
-            slave-label: arm-virtual1
-            installer: fuel
-            <<: *danube
-#--------------------------------
-#        master
-#--------------------------------
-        - arm-pod2:
-            slave-label: arm-pod2
-            installer: fuel
-            <<: *master
-        - arm-pod3:
-            slave-label: arm-pod3
-            installer: fuel
-            <<: *master
-        - arm-pod4:
-            slave-label: arm-pod4
-            installer: fuel
-            <<: *master
-        - arm-virtual1:
-            slave-label: arm-virtual1
-            installer: fuel
-            <<: *master
-#--------------------------------
 #       scenarios
 #--------------------------------
     scenario:
         # HA scenarios
         - 'os-nosdn-nofeature-ha':
             auto-trigger-name: '{installer}-{scenario}-{pod}-{stream}-trigger'
-        - 'os-odl_l2-nofeature-ha':
-            auto-trigger-name: '{installer}-{scenario}-{pod}-{stream}-trigger'
-        - 'os-odl_l3-nofeature-ha':
-            auto-trigger-name: '{installer}-{scenario}-{pod}-{stream}-trigger'
-        - 'os-odl_l2-bgpvpn-ha':
-            auto-trigger-name: '{installer}-{scenario}-{pod}-{stream}-trigger'
-        - 'os-odl_l2-sfc-ha':
+        - 'os-odl-nofeature-ha':
             auto-trigger-name: '{installer}-{scenario}-{pod}-{stream}-trigger'
 
         # NOHA scenarios
-        - 'os-odl_l2-nofeature-noha':
-            auto-trigger-name: '{installer}-{scenario}-{pod}-{stream}-trigger'
-        - 'os-odl_l2-sfc-noha':
+        - 'os-nosdn-nofeature-noha':
             auto-trigger-name: '{installer}-{scenario}-{pod}-{stream}-trigger'
 
     jobs:
             use-build-blocker: true
             blocking-jobs:
                 - '{installer}-os-.*?-{pod}-daily-.*'
+                - 'armband-verify-.*'
             block-level: 'NODE'
 
     wrappers:
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - '{installer}-defaults'
+        - '{installer}-defaults':
+            gs-pathname: '{gs-pathname}'
         - '{slave-label}-defaults':
             installer: '{installer}'
         - string:
             name: DEPLOY_SCENARIO
             default: '{scenario}'
-        - armband-ci-parameter:
-            gs-pathname: '{gs-pathname}'
 
     builders:
         - trigger-builds:
         # 3.only proposed_tests testsuite here(refstack, ha, ipv6, bgpvpn)
         # 4.not used for release criteria or compliance,
         #   only to debug the dovetail tool bugs with arm pods
-        # 5.only run against scenario os-(nosdn|odl_l2)-(nofeature-bgpvpn)-ha
+        # 5.only run against scenario os-(nosdn|odl)-(nofeature-bgpvpn)-ha
         - conditional-step:
             condition-kind: regex-match
-            regex: os-(nosdn|odl_l2)-(nofeature|bgpvpn)-ha
+            regex: os-(nosdn|odl)-(nofeature|bgpvpn)-ha
             label: '{scenario}'
             steps:
                 - trigger-builds:
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - '{installer}-defaults'
+        - '{installer}-defaults':
+            gs-pathname: '{gs-pathname}'
         - '{slave-label}-defaults':
             installer: '{installer}'
         - string:
             name: DEPLOY_SCENARIO
-            default: 'os-odl_l2-nofeature-ha'
-        - armband-ci-parameter:
-            gs-pathname: '{gs-pathname}'
+            default: 'os-odl-nofeature-ha'
 
     scm:
         - git-scm
 
     builders:
         - shell:
-            !include-raw-escape: ./armband-download-artifact.sh
-        - shell:
-            !include-raw-escape: ./armband-deploy.sh
+            !include-raw-escape: ../fuel/fuel-deploy.sh
 
     publishers:
         - email:
             recipients: armband@enea.com
-
-########################
-# parameter macros
-########################
-- parameter:
-    name: armband-ci-parameter
-    parameters:
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
-        - string:
-            name: CACHE_DIRECTORY
-            default: $HOME/opnfv/cache/$INSTALLER_TYPE
-            description: "Directory where the cache to be used during the build is located."
-        - string:
-            name: GS_URL
-            default: artifacts.opnfv.org/$PROJECT{gs-pathname}
-            description: "URL to Google Storage."
+        - email-jenkins-admins-on-failure
 
 ########################
 # trigger macros
 #-----------------------------------------------------------------
 # Enea Armband CI Baremetal Triggers running against master branch
 #-----------------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-armband-baremetal-master-trigger'
-    triggers:
-        - timed: ''
 - trigger:
     name: 'fuel-os-nosdn-nofeature-ha-armband-baremetal-master-trigger'
     triggers:
-        - timed: ''
+        - timed: '0 1 * * *'
 - trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-armband-baremetal-master-trigger'
+    name: 'fuel-os-nosdn-nofeature-noha-armband-baremetal-master-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-armband-baremetal-master-trigger'
+    name: 'fuel-os-odl-nofeature-ha-armband-baremetal-master-trigger'
     triggers:
-        - timed: ''
+        - timed: '0 16 * * *'
+#----------------------------------------------------------------------
+# Enea Armband CI Baremetal Triggers running against euphrates branch
+#----------------------------------------------------------------------
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-armband-baremetal-master-trigger'
+    name: 'fuel-os-nosdn-nofeature-ha-armband-baremetal-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-armband-baremetal-master-trigger'
+    name: 'fuel-os-nosdn-nofeature-noha-armband-baremetal-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-armband-baremetal-master-trigger'
+    name: 'fuel-os-odl-nofeature-ha-armband-baremetal-euphrates-trigger'
     triggers:
         - timed: ''
-
-#----------------------------------------------------------------------
-# Enea Armband CI Baremetal Triggers running against danube branch
-#----------------------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-armband-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 0,16 * * 2,4'
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-armband-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 0 * * 1,5,7'
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-armband-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 16 * * 1,5,7'
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-armband-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 8 * * 2,4,6'
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-armband-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 8 * * 1,3,5,7'
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-armband-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 0 * * 3,6'
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-armband-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 16 * * 3,6'
 #---------------------------------------------------------------
 # Enea Armband CI Virtual Triggers running against master branch
 #---------------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-armband-virtual-master-trigger'
-    triggers:
-        - timed: ''
 - trigger:
     name: 'fuel-os-nosdn-nofeature-ha-armband-virtual-master-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-armband-virtual-master-trigger'
+    name: 'fuel-os-nosdn-nofeature-noha-armband-virtual-master-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-armband-virtual-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-armband-virtual-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-armband-virtual-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-armband-virtual-master-trigger'
+    name: 'fuel-os-odl-nofeature-ha-armband-virtual-master-trigger'
     triggers:
         - timed: ''
 #--------------------------------------------------------------------
-# Enea Armband CI Virtual Triggers running against danube branch
+# Enea Armband CI Virtual Triggers running against euphrates branch
 #--------------------------------------------------------------------
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-armband-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-armband-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-armband-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-armband-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-armband-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-armband-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-armband-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-
-#--------------------------------------------------------------------
-# Enea Armband Non CI Virtual Triggers running against danube branch
-#--------------------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-arm-virtual1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-arm-virtual1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-arm-virtual1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-arm-virtual1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-arm-virtual1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-arm-virtual1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-arm-virtual1-danube-trigger'
-    triggers:
-        - timed: ''
-
-#--------------------------------------------------------------------
-# Enea Armband Non CI Virtual Triggers running against master branch
-#--------------------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-arm-virtual1-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-arm-virtual1-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-arm-virtual1-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-arm-virtual1-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-arm-virtual1-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-arm-virtual1-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-arm-virtual1-master-trigger'
-    triggers:
-        - timed: ''
-
-#----------------------------------------------------------
-# Enea Armband POD 2 Triggers running against master branch
-#----------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-arm-pod2-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-arm-pod2-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-arm-pod2-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-arm-pod2-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-arm-pod2-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-arm-pod2-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-arm-pod2-master-trigger'
-    triggers:
-        - timed: ''
-#---------------------------------------------------------------
-# Enea Armband POD 2 Triggers running against danube branch
-#---------------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-arm-pod2-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-arm-pod2-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-arm-pod2-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-arm-pod2-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-arm-pod2-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-arm-pod2-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-arm-pod2-danube-trigger'
-    triggers:
-        - timed: ''
-#----------------------------------------------------------
-# Enea Armband POD 3 Triggers running against master branch
-#----------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-arm-pod3-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-arm-pod3-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-arm-pod3-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-arm-pod3-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-arm-pod3-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-arm-pod3-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-arm-pod3-master-trigger'
-    triggers:
-        - timed: ''
-#---------------------------------------------------------------
-# Enea Armband POD 3 Triggers running against danube branch
-#---------------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-arm-pod3-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-arm-pod3-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-arm-pod3-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-arm-pod3-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-arm-pod3-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-arm-pod3-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-arm-pod3-danube-trigger'
-    triggers:
-        - timed: ''
-#--------------------------------------------------------------------------
-# Enea Armband POD 3 Triggers running against master branch (aarch64 slave)
-#--------------------------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-arm-pod4-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-arm-pod4-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-arm-pod4-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-arm-pod4-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-arm-pod4-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-arm-pod4-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-arm-pod4-master-trigger'
-    triggers:
-        - timed: ''
-#--------------------------------------------------------------------------
-# Enea Armband POD 3 Triggers running against danube branch (aarch64 slave)
-#--------------------------------------------------------------------------
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-arm-pod4-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-arm-pod4-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-arm-pod4-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-arm-pod4-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-arm-pod4-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-ha-armband-virtual-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-arm-pod4-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-noha-armband-virtual-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-arm-pod4-danube-trigger'
+    name: 'fuel-os-odl-nofeature-ha-armband-virtual-euphrates-trigger'
     triggers:
         - timed: ''
diff --git a/jjb/armband/armband-deploy.sh b/jjb/armband/armband-deploy.sh
deleted file mode 100755 (executable)
index e445e08..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-#           (c) 2016 Enea Software AB
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o nounset
-set -o pipefail
-
-export TERM="vt220"
-
-# source the file so we get OPNFV vars
-source latest.properties
-
-# echo the info about artifact that is used during the deployment
-echo "Using ${OPNFV_ARTIFACT_URL/*\/} for deployment"
-
-if [[ "$JOB_NAME" =~ "merge" ]]; then
-    # set simplest scenario for virtual deploys to run for merges
-    DEPLOY_SCENARIO="os-nosdn-nofeature-ha"
-else
-    # for none-merge deployments
-    # checkout the commit that was used for building the downloaded artifact
-    # to make sure the ISO and deployment mechanism uses same versions
-    echo "Checking out $OPNFV_GIT_SHA1"
-    git checkout $OPNFV_GIT_SHA1 --quiet
-fi
-
-# set deployment parameters
-export TMPDIR=${WORKSPACE}/tmpdir
-
-# arm-pod4 is an aarch64 jenkins slave for the same POD as the
-# x86 jenkins slave arm-pod3; therefore we use the same pod name
-# to deploy the pod from both jenkins slaves
-if [[ "${NODE_NAME}" == "arm-pod4" ]]; then
-    NODE_NAME="arm-pod3"
-fi
-
-LAB_NAME=${NODE_NAME/-*}
-POD_NAME=${NODE_NAME/*-}
-
-# we currently support enea
-if [[ ! $LAB_NAME =~ (arm|enea) ]]; then
-    echo "Unsupported/unidentified lab $LAB_NAME. Cannot continue!"
-    exit 1
-fi
-
-echo "Using configuration for $LAB_NAME"
-
-# create TMPDIR if it doesn't exist
-mkdir -p $TMPDIR
-
-cd $WORKSPACE
-if [[ $LAB_CONFIG_URL =~ ^(git|ssh):// ]]; then
-    echo "Cloning securedlab repo $BRANCH"
-    git clone --quiet --branch $BRANCH $LAB_CONFIG_URL lab-config
-    LAB_CONFIG_URL=file://${WORKSPACE}/lab-config
-
-    # Source local_env if present, which contains POD-specific config
-    local_env="${WORKSPACE}/lab-config/labs/$LAB_NAME/$POD_NAME/fuel/config/local_env"
-    if [ -e $local_env ]; then
-        echo "-- Sourcing local environment file"
-        source $local_env
-    fi
-fi
-
-if [[ "$NODE_NAME" =~ "virtual" ]]; then
-    POD_NAME="virtual_kvm"
-fi
-
-# releng wants us to use nothing else but opnfv.iso for now. We comply.
-ISO_FILE=$WORKSPACE/opnfv.iso
-
-# log file name
-FUEL_LOG_FILENAME="${JOB_NAME}_${BUILD_NUMBER}.log.tar.gz"
-
-# Deploy Cache (to enable just create the deploy-cache subdir)
-# NOTE: Only available when ISO files are cached using ISOSTORE mechanism
-DEPLOY_CACHE=${ISOSTORE:-/iso_mount/opnfv_ci}/${BRANCH##*/}/deploy-cache
-if [[ -d "${DEPLOY_CACHE}" ]]; then
-    echo "Deploy cache dir present."
-    echo "--------------------------------------------------------"
-    echo "Fuel@OPNFV deploy cache: ${DEPLOY_CACHE}"
-    DEPLOY_CACHE="-C ${DEPLOY_CACHE}"
-else
-    DEPLOY_CACHE=""
-fi
-
-# construct the command
-DEPLOY_COMMAND="$WORKSPACE/ci/deploy.sh -b ${LAB_CONFIG_URL} \
-    -l $LAB_NAME -p $POD_NAME -s $DEPLOY_SCENARIO -i file://${ISO_FILE} \
-    -H -B ${DEFAULT_BRIDGE:-pxebr} -S $TMPDIR -L $WORKSPACE/$FUEL_LOG_FILENAME \
-    ${DEPLOY_CACHE}"
-
-# log info to console
-echo "Deployment parameters"
-echo "--------------------------------------------------------"
-echo "Scenario: $DEPLOY_SCENARIO"
-echo "Lab: $LAB_NAME"
-echo "POD: $POD_NAME"
-echo "ISO: ${OPNFV_ARTIFACT_URL/*\/}"
-echo
-echo "Starting the deployment using $INSTALLER_TYPE. This could take some time..."
-echo "--------------------------------------------------------"
-echo
-
-# start the deployment
-echo "Issuing command"
-echo "$DEPLOY_COMMAND"
-echo
-
-$DEPLOY_COMMAND
-exit_code=$?
-
-echo
-echo "--------------------------------------------------------"
-echo "Deployment is done!"
-
-# upload logs for baremetal deployments
-# work with virtual deployments is still going on so we skip that for the timebeing
-if [[ "$JOB_NAME" =~ "baremetal-daily" ]]; then
-    echo "Uploading deployment logs"
-    gsutil cp $WORKSPACE/$FUEL_LOG_FILENAME gs://$GS_URL/logs/$FUEL_LOG_FILENAME > /dev/null 2>&1
-    echo "Logs are available as http://$GS_URL/logs/$FUEL_LOG_FILENAME"
-fi
-
-if [[ $exit_code -ne 0 ]]; then
-    echo "Deployment failed!"
-    exit $exit_code
-else
-    echo "Deployment is successful!"
-fi
diff --git a/jjb/armband/armband-download-artifact.sh b/jjb/armband/armband-download-artifact.sh
deleted file mode 100755 (executable)
index e2dd097..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o errexit
-set -o pipefail
-
-echo "Host info: $(hostname) $(hostname -I)"
-
-# Configurable environment variables:
-# ISOSTORE (/iso_mount/opnfv_ci)
-
-if [[ "$JOB_NAME" =~ "merge" ]]; then
-    echo "Downloading http://$GS_URL/opnfv-gerrit-$GERRIT_CHANGE_NUMBER.properties"
-    # get the properties file for the Armband Fuel ISO built for a merged change
-    curl -f -s -o $WORKSPACE/latest.properties http://$GS_URL/opnfv-gerrit-$GERRIT_CHANGE_NUMBER.properties
-else
-    # get the latest.properties file in order to get info regarding latest artifact
-    echo "Downloading http://$GS_URL/latest.properties"
-    curl -f -s -o $WORKSPACE/latest.properties http://$GS_URL/latest.properties
-fi
-
-# source the file so we get artifact metadata, it will exit if it doesn't exist
-source latest.properties
-
-# echo the info about artifact that is used during the deployment
-OPNFV_ARTIFACT=${OPNFV_ARTIFACT_URL/*\/}
-echo "Using $OPNFV_ARTIFACT for deployment"
-
-# Releng doesn't want us to use anything but opnfv.iso for now. We comply.
-ISO_FILE=${WORKSPACE}/opnfv.iso
-
-# using ISOs for verify & merge jobs from local storage will be enabled later
-if [[ ! "$JOB_NAME" =~ (verify|merge) ]]; then
-    # check if we already have the ISO to avoid redownload
-    ISOSTORE=${ISOSTORE:-/iso_mount/opnfv_ci}/${BRANCH##*/}
-    if [[ -f "$ISOSTORE/$OPNFV_ARTIFACT" ]]; then
-        echo "ISO exists locally. Skipping the download and using the file from ISO store"
-        ln -s $ISOSTORE/$OPNFV_ARTIFACT ${ISO_FILE}
-        echo "--------------------------------------------------------"
-        echo
-        ls -al ${ISO_FILE}
-        echo
-        echo "--------------------------------------------------------"
-        echo "Done!"
-        exit 0
-    fi
-fi
-
-# Use gsutils if available
-if $(which gsutil &>/dev/null); then
-    DOWNLOAD_URL="gs://$OPNFV_ARTIFACT_URL"
-    CMD="gsutil cp ${DOWNLOAD_URL} ${ISO_FILE}"
-else
-    # download image
-    # -f returns error if the file was not found or on server error
-    DOWNLOAD_URL="http://$OPNFV_ARTIFACT_URL"
-    CMD="curl -f -s -o ${ISO_FILE} ${DOWNLOAD_URL}"
-fi
-
-# log info to console
-echo "Downloading the $INSTALLER_TYPE artifact using URL $DOWNLOAD_URL"
-echo "This could take some time..."
-echo "--------------------------------------------------------"
-echo "$CMD"
-$CMD
-echo "--------------------------------------------------------"
-echo "Done!"
diff --git a/jjb/armband/armband-project-jobs.yml b/jjb/armband/armband-project-jobs.yml
deleted file mode 100644 (file)
index f6840a0..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-###################################################
-# All the jobs except verify have been removed!
-# They will only be enabled on request by projects!
-###################################################
-- project:
-    name: armband
-
-    project: '{name}'
-
-    installer: 'fuel'
-
-    jobs:
-        - 'armband-{installer}-build-daily-{stream}'
-
-    stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
-            disabled: false
-        - danube:
-            branch: 'stable/{stream}'
-            gs-pathname: '/{stream}'
-            disabled: false
-
-- job-template:
-    name: 'armband-{installer}-build-daily-{stream}'
-
-    disabled: '{obj:disabled}'
-
-    concurrent: false
-
-    properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 1
-            max-per-node: 1
-            option: 'project'
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-enea-defaults'
-        - '{installer}-defaults'
-        - armband-project-parameter:
-            gs-pathname: '{gs-pathname}'
-
-    scm:
-        - git-scm
-
-    triggers:
-        - pollscm:
-            cron: '0 H/4 * * *'
-
-    wrappers:
-        - timeout:
-            timeout: 360
-            fail: true
-
-    builders:
-        - shell:
-            !include-raw-escape: ./build.sh
-        - shell:
-            !include-raw-escape: ./upload-artifacts.sh
-
-    publishers:
-        - email:
-            recipients: armband@enea.com
-
-########################
-# parameter macros
-########################
-- parameter:
-    name: armband-project-parameter
-    parameters:
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
-        - string:
-            name: CACHE_DIRECTORY
-            default: $HOME/opnfv/cache/$INSTALLER_TYPE
-            description: "Directory where the cache to be used during the build is located."
-        - string:
-            name: GS_URL
-            default: artifacts.opnfv.org/$PROJECT{gs-pathname}
-            description: "URL to Google Storage."
-        - choice:
-            name: FORCE_BUILD
-            choices:
-                - 'false'
-                - 'true'
-            description: 'Force build even if there are no changes in the armband repo. Default false'
index 567456d..c43dc7f 100644 (file)
             branch: '{stream}'
             gs-pathname: ''
             disabled: false
-        - danube:
+        - euphrates:
             branch: 'stable/{stream}'
             gs-pathname: '/{stream}'
-            disabled: false
+            disabled: true
 #####################################
 # patch verification phases
 #####################################
     phase:
         - 'basic':
-            slave-label: 'opnfv-build-enea'
-        - 'build':
-            slave-label: 'opnfv-build-enea'
+            slave-label: 'armband-virtual'
         - 'deploy-virtual':
-            slave-label: 'opnfv-build-enea'
+            slave-label: 'armband-virtual'
         - 'smoke-test':
-            slave-label: 'opnfv-build-enea'
+            slave-label: 'armband-virtual'
 #####################################
 # jobs
 #####################################
             enabled: true
             max-total: 4
             option: 'project'
+        - build-blocker:
+            use-build-blocker: true
+            blocking-jobs:
+                - 'fuel-os-.*?-virtual-daily-.*'
+            block-level: 'NODE'
 
     scm:
         - git-scm-gerrit
@@ -96,8 +99,9 @@
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - 'opnfv-build-enea-defaults'
-        - 'armband-verify-defaults':
+        - 'armband-virtual-defaults':
+            installer: '{installer}'
+        - '{installer}-defaults':
             gs-pathname: '{gs-pathname}'
 
     builders:
                   node-parameters: false
                   kill-phase-on: FAILURE
                   abort-all-job: true
-        - multijob:
-            name: build
-            condition: SUCCESSFUL
-            projects:
-                - name: 'armband-verify-build-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    BRANCH=$BRANCH
-                    GERRIT_REFSPEC=$GERRIT_REFSPEC
-                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
-                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
-                  node-parameters: false
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
         - multijob:
             name: deploy-virtual
             condition: SUCCESSFUL
         - logrotate-default
         - throttle:
             enabled: true
-            max-total: 6
+            max-total: 2
+            max-per-node: 1
             option: 'project'
         - build-blocker:
             use-build-blocker: true
             project: '{project}'
             branch: '{branch}'
         - '{slave-label}-defaults'
-        - '{installer}-defaults'
-        - 'armband-verify-defaults':
+        - 'armband-virtual-defaults':
+            installer: '{installer}'
+        - '{installer}-defaults':
             gs-pathname: '{gs-pathname}'
 
     builders:
 
             echo "Not activated!"
 
-- builder:
-    name: 'armband-verify-build-macro'
-    builders:
-        - shell:
-            !include-raw: ./build.sh
-        - shell:
-            !include-raw: ./armband-workspace-cleanup.sh
-
 - builder:
     name: 'armband-verify-deploy-virtual-macro'
     builders:
-        - shell: |
-            #!/bin/bash
-
-            echo "Not activated!"
+        - shell:
+            !include-raw: ../fuel/fuel-deploy.sh
 
 - builder:
     name: 'armband-verify-smoke-test-macro'
             #!/bin/bash
 
             echo "Not activated!"
-#####################################
-# parameter macros
-#####################################
-- parameter:
-    name: 'armband-verify-defaults'
-    parameters:
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
-        - string:
-            name: CACHE_DIRECTORY
-            default: $HOME/opnfv/cache/$INSTALLER_TYPE
-            description: "Directory where the cache to be used during the build is located."
-        - string:
-            name: GS_URL
-            default: artifacts.opnfv.org/$PROJECT{gs-pathname}
-            description: "URL to Google Storage."
diff --git a/jjb/armband/armband-workspace-cleanup.sh b/jjb/armband/armband-workspace-cleanup.sh
deleted file mode 100755 (executable)
index d8948c7..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o errexit
-set -o nounset
-set -o pipefail
-
-# delete the $WORKSPACE to open some space
-/bin/rm -rf $WORKSPACE
diff --git a/jjb/armband/build.sh b/jjb/armband/build.sh
deleted file mode 100755 (executable)
index a71cf11..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-# Copyright (c) 2016 Enea AB.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o errexit
-set -o nounset
-set -o pipefail
-
-export TERM="vt220"
-
-echo "Host info: $(hostname) $(hostname -I)"
-
-cd $WORKSPACE
-
-# Armband requires initializing git submodules (e.g. for Fuel's clean_cache.sh)
-make submodules-init
-
-# remove the expired items from cache
-test -f $WORKSPACE/ci/clean_cache.sh && $WORKSPACE/ci/clean_cache.sh $CACHE_DIRECTORY
-
-LATEST_ISO_PROPERTIES=$WORKSPACE/latest.iso.properties
-if [[ "$JOB_NAME" =~ "daily" ]]; then
-    # check to see if we already have an artifact on artifacts.opnfv.org
-    # for this commit during daily builds
-    echo "Checking to see if we already built and stored Armband Fuel ISO for this commit"
-
-    curl -s -o $LATEST_ISO_PROPERTIES http://$GS_URL/latest.properties 2>/dev/null
-fi
-
-# get metadata of latest ISO
-if grep -q OPNFV_GIT_SHA1 $LATEST_ISO_PROPERTIES 2>/dev/null; then
-    LATEST_ISO_SHA1=$(grep OPNFV_GIT_SHA1 $LATEST_ISO_PROPERTIES | cut -d'=' -f2)
-    LATEST_ISO_URL=$(grep OPNFV_ARTIFACT_URL $LATEST_ISO_PROPERTIES | cut -d'=' -f2)
-else
-    LATEST_ISO_SHA1=none
-fi
-
-# get current SHA1
-CURRENT_SHA1=$(git rev-parse HEAD)
-
-# set FORCE_BUILD to false for non-daily builds
-FORCE_BUILD=${FORCE_BUILD:-false}
-
-if [[ "$CURRENT_SHA1" == "$LATEST_ISO_SHA1" && "$FORCE_BUILD" == "false" ]]; then
-    echo "***************************************************"
-    echo "   An ISO has already been built for this commit"
-    echo "   $LATEST_ISO_URL"
-    echo "***************************************************"
-else
-    echo "This commit has not been built yet or forced build! Proceeding with the build."
-    /bin/rm -f $LATEST_ISO_PROPERTIES
-    echo
-fi
-
-# log info to console
-echo "Starting the build of Armband $INSTALLER_TYPE. This could take some time..."
-echo "-----------------------------------------------------------"
-echo
-
-# create the cache directory if it doesn't exist
-mkdir -p $CACHE_DIRECTORY
-
-# set OPNFV_ARTIFACT_VERSION
-if [[ "$JOB_NAME" =~ "merge" ]]; then
-    echo "Building Fuel ISO for a merged change"
-    export OPNFV_ARTIFACT_VERSION="gerrit-$GERRIT_CHANGE_NUMBER"
-    echo "Not supported"
-    exit 1
-else
-    export OPNFV_ARTIFACT_VERSION=$(date -u +"%Y-%m-%d_%H-%M-%S")
-fi
-
-NOCACHE_PATTERN="verify: no-cache"
-if [[ "$JOB_NAME" =~ "verify" && "$GERRIT_CHANGE_COMMIT_MESSAGE" =~ "$NOCACHE_PATTERN" ]]; then
-    echo "The cache will not be used for this build!"
-    NOCACHE_ARG="-f P"
-fi
-NOCACHE_ARG=${NOCACHE_ARG:-}
-
-# start the build
-cd $WORKSPACE/ci
-./build.sh -v $OPNFV_ARTIFACT_VERSION $NOCACHE_ARG -c file://$CACHE_DIRECTORY $BUILD_DIRECTORY
-
-# list the build artifacts
-ls -al $BUILD_DIRECTORY
-
-# save information regarding artifact into file
-(
-    echo "OPNFV_ARTIFACT_VERSION=$OPNFV_ARTIFACT_VERSION"
-    echo "OPNFV_GIT_URL=$(git config --get remote.origin.url)"
-    echo "OPNFV_GIT_SHA1=$(git rev-parse HEAD)"
-    echo "OPNFV_ARTIFACT_URL=$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso"
-    echo "OPNFV_ARTIFACT_SHA512SUM=$(sha512sum $BUILD_DIRECTORY/opnfv-$OPNFV_ARTIFACT_VERSION.iso | cut -d' ' -f1)"
-    echo "OPNFV_BUILD_URL=$BUILD_URL"
-) > $WORKSPACE/opnfv.properties
-
-echo
-echo "--------------------------------------------------------"
-echo "Done!"
diff --git a/jjb/armband/upload-artifacts.sh b/jjb/armband/upload-artifacts.sh
deleted file mode 100755 (executable)
index 97987e2..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o pipefail
-
-# configurable environment variables:
-# ISOSTORE (/iso_mount/opnfv_ci)
-
-# check if we built something
-if [ -f $WORKSPACE/.noupload ]; then
-    echo "Nothing new to upload. Exiting."
-    /bin/rm -f $WORKSPACE/.noupload
-    exit 0
-fi
-
-# source the opnfv.properties to get ARTIFACT_VERSION
-source $WORKSPACE/opnfv.properties
-
-
-# storing ISOs for verify & merge jobs will be done once we get the disk array
-if [[ ! "$JOB_NAME" =~ (verify|merge) ]]; then
-    # store ISO locally on NFS first
-    ISOSTORE=${ISOSTORE:-/iso_mount/opnfv_ci}
-    if [[ -d "$ISOSTORE" ]]; then
-        ISOSTORE=${ISOSTORE}/${BRANCH##*/}
-        mkdir -p $ISOSTORE
-
-        # remove all but most recent 3 ISOs first to keep iso_mount clean & tidy
-        cd $ISOSTORE
-        ls -tp | grep -v '/' | tail -n +4 | xargs -d '\n' /bin/rm -f --
-
-        # store ISO
-        echo "Storing latest ISO in local storage"
-        touch .storing
-        /bin/cp -f $BUILD_DIRECTORY/opnfv-$OPNFV_ARTIFACT_VERSION.iso \
-            $ISOSTORE/opnfv-$OPNFV_ARTIFACT_VERSION.iso
-        rm .storing
-    fi
-fi
-
-# log info to console
-echo "Uploading armband artifacts. This could take some time..."
-echo
-
-echo "Started at $(date)"
-cd $WORKSPACE
-# upload artifact and additional files to google storage
-gsutil cp $BUILD_DIRECTORY/opnfv-$OPNFV_ARTIFACT_VERSION.iso \
-    gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso > gsutil.iso.log 2>&1
-gsutil cp $WORKSPACE/opnfv.properties \
-    gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.properties > gsutil.properties.log 2>&1
-if [[ ! "$JOB_NAME" =~ (verify|merge) ]]; then
-    gsutil cp $WORKSPACE/opnfv.properties \
-    gs://$GS_URL/latest.properties > gsutil.latest.log 2>&1
-elif [[ "$JOB_NAME" =~ "merge" ]]; then
-    echo "Uploaded Armband Fuel ISO for a merged change"
-fi
-echo "Ended at $(date)"
-
-gsutil -m setmeta \
-    -h "Content-Type:text/html" \
-    -h "Cache-Control:private, max-age=0, no-transform" \
-    gs://$GS_URL/latest.properties \
-    gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.properties > /dev/null 2>&1
-
-gsutil -m setmeta \
-    -h "Cache-Control:private, max-age=0, no-transform" \
-    gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso > /dev/null 2>&1
-
-# disabled errexit due to gsutil setmeta complaints
-#   BadRequestException: 400 Invalid argument
-# check if we uploaded the file successfully to see if things are fine
-gsutil ls gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso > /dev/null 2>&1
-if [[ $? -ne 0 ]]; then
-    echo "Problem while uploading artifact!"
-    echo "Check log $WORKSPACE/gsutil.iso.log on the machine where this build is done."
-    exit 1
-fi
-
-echo "Done!"
-echo
-echo "--------------------------------------------------------"
-echo
-echo "Artifact is available as http://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso"
-echo
-echo "--------------------------------------------------------"
-echo
diff --git a/jjb/auto/auto.yml b/jjb/auto/auto.yml
new file mode 100644 (file)
index 0000000..fefa376
--- /dev/null
@@ -0,0 +1,56 @@
+---
+- project:
+    name: auto
+
+    project: '{name}'
+
+    stream:
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
+
+    jobs:
+      - 'auto-verify-{stream}'
+
+- job-template:
+    name: 'auto-verify-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    parameters:
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'opnfv-build-defaults'
+
+    scm:
+      - git-scm-gerrit
+
+    triggers:
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: 'recheck'
+            - comment-added-contains-event:
+                comment-contains-value: 'reverify'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              disable-strict-forbidden-file-verification: 'true'
+              forbidden-file-paths:
+                - compare-type: ANT
+                  pattern: 'docs/**|.gitignore'
+
+    builders:
+      - shell: |
+          echo "Nothing to verify!"
index 2d3e972..8a5bea0 100644 (file)
@@ -1,3 +1,4 @@
+---
 ###################################################
 # All the jobs except verify have been removed!
 # They will only be enabled on request by projects!
@@ -8,19 +9,19 @@
     project: '{name}'
 
     jobs:
-        - 'barometer-verify-{stream}'
-        - 'barometer-merge-{stream}'
-        - 'barometer-daily-{stream}'
+      - 'barometer-verify-{stream}'
+      - 'barometer-merge-{stream}'
+      - 'barometer-daily-{stream}'
 
     stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
-            disabled: false
-        - danube:
-            branch: 'stable/{stream}'
-            gs-pathname: '/{stream}'
-            disabled: false
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
+      - danube:
+          branch: 'stable/{stream}'
+          gs-pathname: '/{stream}'
+          disabled: false
 
 - job-template:
     name: 'barometer-verify-{stream}'
     disabled: '{obj:disabled}'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'opnfv-build-ubuntu-defaults'
 
     scm:
-        - git-scm-gerrit
+      - git-scm-gerrit
 
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - patchset-created-event:
-                    exclude-drafts: 'false'
-                    exclude-trivial-rebase: 'false'
-                    exclude-no-code-change: 'false'
-                - draft-published-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'recheck'
-                - comment-added-contains-event:
-                    comment-contains-value: 'reverify'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-                disable-strict-forbidden-file-verification: 'true'
-                forbidden-file-paths:
-                  - compare-type: ANT
-                    pattern: 'docs/**|.gitignore'
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: 'recheck'
+            - comment-added-contains-event:
+                comment-contains-value: 'reverify'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              disable-strict-forbidden-file-verification: 'true'
+              forbidden-file-paths:
+                - compare-type: ANT
+                  pattern: 'docs/**|.gitignore'
 
     builders:
-        - shell: |
-            pwd
-            cd src
-            make clobber
-            make
+      - shell: |
+          pwd
+          cd src
+          make clobber
+          make
 
 - job-template:
     name: 'barometer-merge-{stream}'
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 3
-            max-per-node: 2
-            option: 'project'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 3
+          max-per-node: 2
+          option: 'project'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'opnfv-build-ubuntu-defaults'
 
     scm:
-        - git-scm
+      - git-scm
 
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - change-merged-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'remerge'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                    - branch-compare-type: 'ANT'
-                      branch-pattern: '**/{branch}'
-                disable-strict-forbidden-file-verification: 'true'
-                forbidden-file-paths:
-                  - compare-type: ANT
-                    pattern: 'docs/**'
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - change-merged-event
+            - comment-added-contains-event:
+                comment-contains-value: 'remerge'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              disable-strict-forbidden-file-verification: 'true'
+              forbidden-file-paths:
+                - compare-type: ANT
+                  pattern: 'docs/**'
 
     builders:
-        - shell: |
-            pwd
-            cd src
-            make clobber
-            make
+      - shell: |
+          pwd
+          cd src
+          make clobber
+          make
 
 - job-template:
     name: 'barometer-daily-{stream}'
     concurrent: false
 
     properties:
-        - logrotate-default
+      - logrotate-default
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - barometer-project-parameter:
-            gs-pathname: '{gs-pathname}'
-        - 'opnfv-build-centos-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - barometer-project-parameter:
+          gs-pathname: '{gs-pathname}'
+      - 'opnfv-build-centos-defaults'
 
     scm:
-        - git-scm
+      - git-scm
 
     triggers:
-         - timed: '@midnight'
+      - timed: '@midnight'
 
     builders:
-        - shell:
-            !include-raw-escape: ./barometer-build.sh
-        - shell:
-            !include-raw-escape: ./barometer-upload-artifact.sh
+      - shell:
+          !include-raw-escape: ./barometer-build.sh
+      - shell:
+          !include-raw-escape: ./barometer-upload-artifact.sh
 
 ########################
 # parameter macros
 - parameter:
     name: barometer-project-parameter
     parameters:
-        - string:
-            name: GS_URL
-            default: '$GS_BASE{gs-pathname}'
-            description: "URL to Google Storage."
+      - string:
+          name: GS_URL
+          default: '$GS_BASE{gs-pathname}'
+          description: "URL to Google Storage."
index c56ca19..a8654d0 100644 (file)
@@ -1,3 +1,4 @@
+---
 ####################################
 # job configuration for bottlenecks
 ####################################
@@ -6,77 +7,75 @@
 
     project: 'bottlenecks'
 
-#--------------------------------
-# BRANCH ANCHORS
-#--------------------------------
+    # -------------------------------
+    # BRANCH ANCHORS
+    # -------------------------------
     master: &master
-        stream: master
-        branch: '{stream}'
-        #This is used for common project file storage
-        gs-pathname: ''
-        #This is used for different test suite dependent packages storage
-        gs-packagepath: '/{suite}'
-        #docker tag used for version control
-        docker-tag: 'latest'
+      stream: master
+      branch: '{stream}'
+      This is used for common project file storage
+      gs-pathname: ''
+      This is used for different test suite dependent packages storage
+      gs-packagepath: '/{suite}'
+      docker tag used for version control
+      docker-tag: 'latest'
     danube: &danube
-        stream: danube
-        branch: 'stable/{stream}'
-        gs-pathname: '/{stream}'
-        gs-packagepath: '/{stream}/{suite}'
-        docker-tag: 'stable'
-#--------------------------------
-# POD, INSTALLER, AND BRANCH MAPPING
-#--------------------------------
-#    Installers using labels
-#            CI PODs
-# This section should only contain the installers
-# that have been switched using labels for slaves
-#--------------------------------
+      stream: danube
+      branch: 'stable/{stream}'
+      gs-pathname: '/{stream}'
+      gs-packagepath: '/{stream}/{suite}'
+      docker-tag: 'stable'
+    # -------------------------------
+    # POD, INSTALLER, AND BRANCH MAPPING
+    # -------------------------------
+    #    Installers using labels
+    #            CI PODs
+    # This section should only contain the installers
+    # that have been switched using labels for slaves
+    # -------------------------------
     pod:
-#compass CI PODs
-        - baremetal:
-            slave-label: compass-baremetal
-            installer: compass
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *master
-        - virtual:
-            slave-label: compass-virtual
-            installer: compass
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *master
-        - baremetal:
-            slave-label: compass-baremetal
-            installer: compass
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *danube
-        - virtual:
-            slave-label: compass-virtual
-            installer: compass
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *danube
-
-#--------------------------------
-#        None-CI PODs
-#--------------------------------
-       # - orange-pod2:
-       #     slave-label: '{pod}'
-       #     installer: joid
-       #     auto-trigger-name: 'daily-trigger-disabled'
-       #     <<: *danube
-       # - orange-pod2:
-       #     slave-label: '{pod}'
-       #     installer: joid
-       #     auto-trigger-name: 'daily-trigger-disabled'
-       #     <<: *master
-#--------------------------------------------
+      # compass CI PODs
+      - baremetal:
+          slave-label: compass-baremetal-master
+          installer: compass
+          auto-trigger-name: 'daily-trigger-disabled'
+          <<: *master
+      - virtual:
+          slave-label: compass-virtual-master
+          installer: compass
+          auto-trigger-name: 'daily-trigger-disabled'
+          <<: *master
+      - baremetal:
+          slave-label: compass-baremetal-branch
+          installer: compass
+          auto-trigger-name: 'daily-trigger-disabled'
+          <<: *danube
+      - virtual:
+          slave-label: compass-virtual-branch
+          installer: compass
+          auto-trigger-name: 'daily-trigger-disabled'
+          <<: *danube
+
+    # -------------------------------
+    #        None-CI PODs
+    # -------------------------------
+    # - orange-pod2:
+    #     slave-label: '{pod}'
+    #     installer: joid
+    #     auto-trigger-name: 'daily-trigger-disabled'
+    #     <<: *danube
+    # - orange-pod2:
+    #     slave-label: '{pod}'
+    #     installer: joid
+    #     auto-trigger-name: 'daily-trigger-disabled'
+    #     <<: *master
+    # -------------------------------------------
     suite:
-        - 'rubbos'
-        - 'vstf'
-        - 'posca_stress_traffic'
-        - 'posca_stress_ping'
+      - 'posca_stress_traffic'
+      - 'posca_stress_ping'
 
     jobs:
-        - 'bottlenecks-{installer}-{suite}-{pod}-daily-{stream}'
+      - 'bottlenecks-{installer}-{suite}-{pod}-daily-{stream}'
 
 ################################
 # job templates
     name: 'bottlenecks-{installer}-{suite}-{pod}-daily-{stream}'
 
     wrappers:
-        - build-name:
-            name: '$BUILD_NUMBER - Scenario: $DEPLOY_SCENARIO'
-        - timeout:
-            timeout: 180
-            abort: true
+      - build-name:
+          name: '$BUILD_NUMBER - Scenario: $DEPLOY_SCENARIO'
+      - timeout:
+          timeout: 180
+          abort: true
 
     triggers:
-        - '{auto-trigger-name}'
+      - '{auto-trigger-name}'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - '{slave-label}-defaults'
-        - '{installer}-defaults'
-        - 'bottlenecks-params-{slave-label}'
-        - string:
-            name: REPO_DIR
-            default: "/home/opnfv/bottlenecks"
-            description: "Directory where the repository is cloned"
-        - string:
-            name: DEPLOY_SCENARIO
-            default: 'os-odl_l2-nofeature-ha'
-        - string:
-            name: GERRIT_REFSPEC_DEBUG
-            default: 'true'
-            description: "Gerrit refspec for debug."
-        - string:
-            name: SUITE_NAME
-            default: '{suite}'
-            description: "test suite name."
-        - string:
-            name: DOCKER_TAG
-            default: '{docker-tag}'
-            description: "docker image tag used for version control"
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - '{slave-label}-defaults'
+      - '{installer}-defaults'
+      - 'bottlenecks-params-{slave-label}'
+      - string:
+          name: REPO_DIR
+          default: "/home/opnfv/bottlenecks"
+          description: "Directory where the repository is cloned"
+      - string:
+          name: DEPLOY_SCENARIO
+          default: 'os-odl_l2-nofeature-ha'
+      - string:
+          name: GERRIT_REFSPEC_DEBUG
+          default: 'true'
+          description: "Gerrit refspec for debug."
+      - string:
+          name: SUITE_NAME
+          default: '{suite}'
+          description: "test suite name."
+      - string:
+          name: DOCKER_TAG
+          default: '{docker-tag}'
+          description: "docker image tag used for version control"
 
     scm:
-        - git-scm
+      - git-scm
 
     builders:
-        - 'bottlenecks-env-cleanup'
-        - 'bottlenecks-run-suite'
+      - 'bottlenecks-env-cleanup'
+      - 'bottlenecks-run-suite'
 
     publishers:
-        - email:
-            recipients: hongbo.tianhongbo@huawei.com matthew.lijun@huawei.com liangqi1@huawei.com sunshine.wang@huawei.com
+      - email:
+          recipients: gabriel.yuyang@huawei.com, liyin11@huawei.com
+      - email-jenkins-admins-on-failure
 
 ########################
 # builder macros
 - builder:
     name: bottlenecks-env-cleanup
     builders:
-        - shell:
-            !include-raw: ./bottlenecks-cleanup.sh
+      - shell:
+          !include-raw: ./bottlenecks-cleanup.sh
 
 - builder:
     name: bottlenecks-run-suite
     builders:
-        - shell:
-            !include-raw: ./bottlenecks-run-suite.sh
+      - shell:
+          !include-raw: ./bottlenecks-run-suite.sh
 
 ####################
 # parameter macros
 ####################
 
 - parameter:
-    name: 'bottlenecks-params-compass-baremetal'
+    name: 'bottlenecks-params-compass-baremetal-master'
     parameters:
-        - string:
-            name: BOTTLENECKS_DB_TARGET
-            default: '104.197.68.199:8086'
-            description: 'Arguments to use in order to choose the backend DB'
+      - string:
+          name: BOTTLENECKS_DB_TARGET
+          default: 'http://testresults.opnfv.org/test/api/v1/results'
+          description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'bottlenecks-params-compass-virtual'
+    name: 'bottlenecks-params-compass-virtual-master'
     parameters:
-        - string:
-            name: BOTTLENECKS_DB_TARGET
-            default: ''
-            description: 'Arguments to use in order to choose the backend DB'
+      - string:
+          name: BOTTLENECKS_DB_TARGET
+          default: 'http://testresults.opnfv.org/test/api/v1/results'
+          description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'bottlenecks-params-orange-pod2'
+    name: 'bottlenecks-params-compass-baremetal-branch'
     parameters:
-        - string:
-            name: BOTTLENECKS_DB_TARGET
-            default: '104.197.68.199:8086'
-            description: 'Arguments to use in order to choose the backend DB'
+      - string:
+          name: BOTTLENECKS_DB_TARGET
+          default: 'http://testresults.opnfv.org/test/api/v1/results'
+          description: 'Arguments to use in order to choose the backend DB'
+
+- parameter:
+    name: 'bottlenecks-params-compass-virtual-branch'
+    parameters:
+      - string:
+          name: BOTTLENECKS_DB_TARGET
+          default: 'http://testresults.opnfv.org/test/api/v1/results'
+          description: 'Arguments to use in order to choose the backend DB'
index 04e620c..d0e2088 100644 (file)
@@ -10,6 +10,7 @@
 
 #clean up correlated dockers and their images
 bash $WORKSPACE/docker/docker_cleanup.sh -d bottlenecks --debug
+bash $WORKSPACE/docker/docker_cleanup.sh -d Bottlenecks --debug
 bash $WORKSPACE/docker/docker_cleanup.sh -d yardstick --debug
 bash $WORKSPACE/docker/docker_cleanup.sh -d kibana --debug
 bash $WORKSPACE/docker/docker_cleanup.sh -d elasticsearch --debug
index 5dced2a..c7c9b42 100644 (file)
@@ -1,3 +1,4 @@
+---
 ###################################################
 # Non-ci jobs for Bottlenecks project
 # They will only be enabled on request by projects!
@@ -8,29 +9,29 @@
     project: 'bottlenecks'
 
     jobs:
-        - 'bottlenecks-verify-{stream}'
-        - 'bottlenecks-merge-{stream}'
-        - 'bottlenecks-{suite}-upload-artifacts-{stream}'
+      - 'bottlenecks-verify-{stream}'
+      - 'bottlenecks-merge-{stream}'
+      - 'bottlenecks-{suite}-upload-artifacts-{stream}'
 
     stream:
-        - master:
-            branch: '{stream}'
-            #This is used for common project file storage
-            gs-pathname: ''
-            #This is used for different test suite dependent packages storage
-            gs-packagepath: '/{suite}'
-            disabled: false
-        - danube:
-            branch: 'stable/{stream}'
-            gs-pathname: '/{stream}'
-            gs-packagepath: '/{stream}/{suite}'
-            disabled: false
+      - master:
+          branch: '{stream}'
+          This is used for common project file storage
+          gs-pathname: ''
+          This is used for different test suite dependent packages storage
+          gs-packagepath: '/{suite}'
+          disabled: false
+      - danube:
+          branch: 'stable/{stream}'
+          gs-pathname: '/{stream}'
+          gs-packagepath: '/{stream}/{suite}'
+          disabled: false
 
     suite:
-        - 'rubbos'
-        - 'vstf'
-        - 'posca_stress_traffic'
-        - 'posca_stress_ping'
+      - 'rubbos'
+      - 'vstf'
+      - 'posca_stress_traffic'
+      - 'posca_stress_ping'
 
 ################################
 # job templates
     disabled: '{obj:disabled}'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'opnfv-build-ubuntu-defaults'
 
     scm:
-        - git-scm-gerrit
+      - git-scm-gerrit
 
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - patchset-created-event:
-                    exclude-drafts: 'false'
-                    exclude-trivial-rebase: 'false'
-                    exclude-no-code-change: 'false'
-                - draft-published-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'recheck'
-                - comment-added-contains-event:
-                    comment-contains-value: 'reverify'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: 'recheck'
+            - comment-added-contains-event:
+                comment-contains-value: 'reverify'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+
     builders:
-        #- bottlenecks-hello
-        - bottlenecks-unit-tests
+      - bottlenecks-hello
+      - bottlenecks-unit-tests
 
 - job-template:
     name: 'bottlenecks-merge-{stream}'
     disabled: '{obj:disabled}'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'opnfv-build-ubuntu-defaults'
 
     scm:
-        - git-scm
+      - git-scm
 
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - change-merged-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'remerge'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                    - branch-compare-type: 'ANT'
-                      branch-pattern: '**/{branch}'
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - change-merged-event
+            - comment-added-contains-event:
+                comment-contains-value: 'remerge'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
 
     builders:
-        - bottlenecks-hello
-        #- bottlenecks-unit-tests
+      - bottlenecks-hello
+      - bottlenecks-unit-tests
 
 - job-template:
     name: 'bottlenecks-{suite}-upload-artifacts-{stream}'
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 1
-            max-per-node: 1
-            option: 'project'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 1
+          max-per-node: 1
+          option: 'project'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
-        - bottlenecks-parameter:
-            gs-packagepath: '{gs-packagepath}'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'opnfv-build-ubuntu-defaults'
+      - bottlenecks-parameter:
+          gs-packagepath: '{gs-packagepath}'
 
     scm:
-        - git-scm
+      - git-scm
 
     builders:
-        - 'bottlenecks-builder-upload-artifact'
-        - 'bottlenecks-workspace-cleanup'
+      - 'bottlenecks-builder-upload-artifact'
+      - 'bottlenecks-workspace-cleanup'
 
 ####################
 # parameter macros
 - parameter:
     name: bottlenecks-parameter
     parameters:
-        - string:
-           name: CACHE_DIR
-           default: $WORKSPACE/cache{gs-packagepath}
-           description: "the cache to store packages downloaded from public IP"
-        - string:
-           name: SUITE_URL
-           default: gs://artifacts.opnfv.org/bottlenecks{gs-packagepath}
-           description: "LF artifacts url for storage of bottlenecks packages"
-        - string:
-           name: PACKAGE_URL
-           default: http://205.177.226.237:9999/bottlenecks{gs-packagepath}/
-           description: "the url where we store the packages used for bottlenecks rubbos"
+      - string:
+          name: CACHE_DIR
+          default: $WORKSPACE/cache{gs-packagepath}
+          description: "the cache to store packages downloaded from public IP"
+      - string:
+          name: SUITE_URL
+          default: gs://artifacts.opnfv.org/bottlenecks{gs-packagepath}
+          description: "LF artifacts url for storage of bottlenecks packages"
+      - string:
+          name: PACKAGE_URL
+          default: http://205.177.226.237:9999/bottlenecks{gs-packagepath}/
+          description: "the url where we store the packages used for bottlenecks rubbos"
 
 ####################################
-#builders for bottlenecks project
+# builders for bottlenecks project
 ####################################
 - builder:
     name: bottlenecks-builder-upload-artifact
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
+      - shell: |
+          #!/bin/bash
+          set -o errexit
 
-            echo "Bottlenecks: upload to artifacts from the public IP"
+          echo "Bottlenecks: upload to artifacts from the public IP"
 
-            [[ -d $CACHE_DIR ]] || mkdir -p $CACHE_DIR
+          [[ -d $CACHE_DIR ]] || mkdir -p $CACHE_DIR
 
-            for file in $(curl -s $PACKAGE_URL |
-                               grep href |
-                               sed 's/.*href="//' |
-                               sed 's/".*//' |
-                               grep '^[a-zA-Z].*'); do
-                 curl --connect-timeout 10 -o $CACHE_DIR/$file $PACKAGE_URL$file -v
-                 echo "bottlenecks: copy file $CACHE_DIR/$file to $SUITE_URL"
-                 gsutil cp $CACHE_DIR/$file $SUITE_URL
-            done
+          for file in $(curl -s $PACKAGE_URL |
+                             grep href |
+                             sed 's/.*href="//' |
+                             sed 's/".*//' |
+                             grep '^[a-zA-Z].*'); do
+               curl --connect-timeout 10 -o $CACHE_DIR/$file $PACKAGE_URL$file -v
+               echo "bottlenecks: copy file $CACHE_DIR/$file to $SUITE_URL"
+               gsutil cp $CACHE_DIR/$file $SUITE_URL
+          done
 
 - builder:
     name: bottlenecks-workspace-cleanup
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
+      - shell: |
+          #!/bin/bash
+          set -o errexit
 
-            echo "Bottlenecks: cleanup cache used for storage downloaded packages"
+          echo "Bottlenecks: cleanup cache used for storage downloaded packages"
 
-            /bin/rm -rf $CACHE_DIR
+          /bin/rm -rf $CACHE_DIR
 
 - builder:
     name: bottlenecks-unit-tests
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o pipefail
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o pipefail
 
-            echo "Running unit tests..."
-            cd $WORKSPACE
-            virtualenv $WORKSPACE/bottlenecks_venv
-            source $WORKSPACE/bottlenecks_venv/bin/activate
+          echo "Running unit tests..."
+          cd $WORKSPACE
+          virtualenv $WORKSPACE/bottlenecks_venv
+          source $WORKSPACE/bottlenecks_venv/bin/activate
 
-            # install python packages
-            easy_install -U setuptools
-            easy_install -U pip
-            pip install -r $WORKSPACE/requirements/verify.txt
+          # install python packages
+          easy_install -U setuptools
+          easy_install -U pip
+          pip install -r $WORKSPACE/requirements/verify.txt
 
-            # unit tests
-            /bin/bash $WORKSPACE/verify.sh
+          # unit tests
+          /bin/bash $WORKSPACE/verify.sh
 
-            deactivate
+          deactivate
 
 - builder:
     name: bottlenecks-hello
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
+      - shell: |
+          #!/bin/bash
+          set -o errexit
 
-            echo -e "Wellcome to Bottlenecks! \nMerge event is planning to support more functions! "
+          echo -e "Wellcome to Bottlenecks! \nMerge event is planning to support more functions! "
index e6f8d1b..6d4d2d8 100644 (file)
 #!/bin/bash
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
 #set -e
 [[ $GERRIT_REFSPEC_DEBUG == true ]] && redirect="/dev/stdout" || redirect="/dev/null"
 BOTTLENECKS_IMAGE=opnfv/bottlenecks
 REPORT="True"
 
-if [[ $SUITE_NAME == rubbos || $SUITE_NAME == vstf ]]; then
-    echo "Bottlenecks: to pull image $BOTTLENECKS_IMAGE:${DOCKER_TAG}"
-    docker pull $BOTTLENECKS_IMAGE:$DOCKER_TAG >${redirect}
+RELENG_REPO=${WORKSPACE}/releng
+[ -d ${RELENG_REPO} ] && rm -rf ${RELENG_REPO}
+git clone https://gerrit.opnfv.org/gerrit/releng ${RELENG_REPO} >${redirect}
 
-    echo "Bottlenecks: docker start running"
-    opts="--privileged=true -id"
-    envs="-e INSTALLER_TYPE=${INSTALLER_TYPE} -e INSTALLER_IP=${INSTALLER_IP} \
-          -e NODE_NAME=${NODE_NAME} -e EXTERNAL_NET=${EXTERNAL_NETWORK} \
-          -e BOTTLENECKS_BRANCH=${BOTTLENECKS_BRANCH} -e GERRIT_REFSPEC_DEBUG=${GERRIT_REFSPEC_DEBUG} \
-          -e BOTTLENECKS_DB_TARGET=${BOTTLENECKS_DB_TARGET} -e PACKAGE_URL=${PACKAGE_URL}"
-    cmd="sudo docker run ${opts} ${envs} $BOTTLENECKS_IMAGE:${DOCKER_TAG} /bin/bash"
-    echo "Bottlenecks: docker cmd running ${cmd}"
-    ${cmd} >${redirect}
-
-    echo "Bottlenecks: obtain docker id"
-    container_id=$(docker ps | grep "$BOTTLENECKS_IMAGE:${DOCKER_TAG}" | awk '{print $1}' | head -1)
-    if [ -z ${container_id} ]; then
-        echo "Cannot find $BOTTLENECKS_IMAGE container ID ${container_id}. Please check if it exists."
-        docker ps -a
+YARDSTICK_REPO=${WORKSPACE}/yardstick
+[ -d ${YARDSTICK_REPO} ] && rm -rf ${YARDSTICK_REPO}
+git clone https://gerrit.opnfv.org/gerrit/yardstick ${YARDSTICK_REPO} >${redirect}
+
+OPENRC=/tmp/admin_rc.sh
+OS_CACERT=/tmp/os_cacert
+
+BOTTLENECKS_CONFIG=/tmp
+
+if [[ $SUITE_NAME == *posca* ]]; then
+    POSCA_SCRIPT=/home/opnfv/bottlenecks/testsuites/posca
+
+    # Preparing OpenStack RC and Cacert files
+    echo "BOTTLENECKS INFO: fetching os credentials from $INSTALLER_TYPE"
+    if [[ $INSTALLER_TYPE == 'compass' ]]; then
+        if [[ ${BRANCH} == 'master' ]]; then
+            ${RELENG_REPO}/utils/fetch_os_creds.sh -d ${OPENRC} -i ${INSTALLER_TYPE} -a ${INSTALLER_IP} -o ${OS_CACERT} >${redirect}
+            if [[ -f ${OS_CACERT} ]]; then
+                echo "BOTTLENECKS INFO: successfully fetching os_cacert for openstack: ${OS_CACERT}"
+            else
+                echo "BOTTLENECKS ERROR: couldn't find os_cacert file: ${OS_CACERT}, please check if the it's been properly provided."
+                exit 1
+            fi
+        else
+            ${RELENG_REPO}/utils/fetch_os_creds.sh -d ${OPENRC} -i ${INSTALLER_TYPE} -a ${INSTALLER_IP}  >${redirect}
+        fi
+    fi
+
+    if [[ -f ${OPENRC} ]]; then
+        echo "BOTTLENECKS INFO: openstack credentials path is ${OPENRC}"
+        if [[ $INSTALLER_TYPE == 'compass' && ${BRANCH} == 'master' ]]; then
+            echo "BOTTLENECKS INFO: writing ${OS_CACERT} to ${OPENRC}"
+            echo "export OS_CACERT=${OS_CACERT}" >> ${OPENRC}
+        fi
+        cat ${OPENRC}
+    else
+        echo "BOTTLENECKS ERROR: couldn't find openstack rc file: ${OPENRC}, please check if the it's been properly provided."
         exit 1
     fi
 
-    echo "Bottlenecks: to prepare openstack environment"
-    prepare_env="${REPO_DIR}/ci/prepare_env.sh"
-    echo "Bottlenecks: docker cmd running: ${prepare_env}"
-    sudo docker exec ${container_id} ${prepare_env}
-
-    echo "Bottlenecks: to run testsuite ${SUITE_NAME}"
-    run_testsuite="${REPO_DIR}/run_tests.sh -s ${SUITE_NAME}"
-    echo "Bottlenecks: docker cmd running: ${run_testsuite}"
-    sudo docker exec ${container_id} ${run_testsuite}
-else
-    echo "Bottlenecks: installing POSCA docker-compose"
-    if [ -d usr/local/bin/docker-compose ]; then
-        rm -rf usr/local/bin/docker-compose
+    # Finding and crearting POD description files from different deployments
+    ssh_options="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
+
+    if [ "$INSTALLER_TYPE" == "fuel" ]; then
+        echo "Fetching id_rsa file from jump_server $INSTALLER_IP..."
+        sshpass -p r00tme sudo scp $ssh_options root@${INSTALLER_IP}:~/.ssh/id_rsa ${BOTTLENECKS_CONFIG}/id_rsa
+    fi
+
+    if [ "$INSTALLER_TYPE" == "apex" ]; then
+        echo "Fetching id_rsa file from jump_server $INSTALLER_IP..."
+        sudo scp $ssh_options stack@${INSTALLER_IP}:~/.ssh/id_rsa ${BOTTLENECKS_CONFIG}/id_rsa
     fi
-    curl -L https://github.com/docker/compose/releases/download/1.11.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
-    chmod +x /usr/local/bin/docker-compose
 
-    echo "Bottlenecks: composing up dockers"
-    cd $WORKSPACE
-    docker-compose -f $WORKSPACE/docker/bottleneck-compose/docker-compose.yml up -d
+    set +e
 
-    echo "Bottlenecks: running traffic stress/factor testing in posca testsuite "
-    POSCA_SCRIPT=/home/opnfv/bottlenecks/testsuites/posca
+    sudo pip install virtualenv
+
+    cd ${RELENG_REPO}/modules
+    sudo virtualenv venv
+    source venv/bin/activate
+    sudo pip install -e ./ >/dev/null
+    sudo pip install netaddr
+
+    if [[ ${INSTALLER_TYPE} == compass ]]; then
+        options="-u root -p root"
+    elif [[ ${INSTALLER_TYPE} == fuel ]]; then
+        options="-u root -p r00tme"
+    elif [[ ${INSTALLER_TYPE} == apex ]]; then
+        options="-u stack -k /root/.ssh/id_rsa"
+    else
+        echo "Don't support to generate pod.yaml on ${INSTALLER_TYPE} currently."
+    fi
+
+    if [[ ${INSTALLER_TYPE} != compass ]]; then
+        cmd="sudo python ${RELENG_REPO}/utils/create_pod_file.py -t ${INSTALLER_TYPE} \
+         -i ${INSTALLER_IP} ${options} -f ${BOTTLENECKS_CONFIG}/pod.yaml \
+         -s ${BOTTLENECKS_CONFIG}/id_rsa"
+        echo ${cmd}
+        ${cmd}
+    else
+        cmd="sudo cp ${YARDSTICK_REPO}/etc/yardstick/nodes/compass_sclab_virtual/pod.yaml \
+        ${BOTTLENECKS_CONFIG}"
+        echo ${cmd}
+        ${cmd}
+    fi
+
+    deactivate
+
+    set -e
+
+    cd ${WORKSPACE}
+
+    if [ -f ${BOTTLENECKS_CONFIG}/pod.yaml ]; then
+        echo "FILE: ${BOTTLENECKS_CONFIG}/pod.yaml:"
+        cat ${BOTTLENECKS_CONFIG}/pod.yaml
+    else
+        echo "ERROR: cannot find file ${BOTTLENECKS_CONFIG}/pod.yaml. Please check if it is existing."
+        sudo ls -al ${BOTTLENECKS_CONFIG}
+    fi
+
+    # Pulling Bottlenecks docker and passing environment variables
+    echo "INFO: pulling Bottlenecks docker ${DOCKER_TAG}"
+    docker pull opnfv/bottlenecks:${DOCKER_TAG} >$redirect
+
+    opts="--privileged=true -id"
+    envs="-e INSTALLER_TYPE=${INSTALLER_TYPE} -e INSTALLER_IP=${INSTALLER_IP} \
+          -e NODE_NAME=${NODE_NAME} -e EXTERNAL_NET=${EXTERNAL_NETWORK} \
+          -e BRANCH=${BRANCH} -e GERRIT_REFSPEC_DEBUG=${GERRIT_REFSPEC_DEBUG} \
+          -e BOTTLENECKS_DB_TARGET=${BOTTLENECKS_DB_TARGET} -e PACKAGE_URL=${PACKAGE_URL} \
+          -e DEPLOY_SCENARIO=${DEPLOY_SCENARIO} -e BUILD_TAG=${BUILD_TAG}"
+    docker_volume="-v /var/run/docker.sock:/var/run/docker.sock -v /tmp:/tmp"
+
+    cmd="docker run ${opts} ${envs} --name bottlenecks-load-master ${docker_volume} opnfv/bottlenecks:${DOCKER_TAG} /bin/bash"
+    echo "BOTTLENECKS INFO: running docker run commond: ${cmd}"
+    ${cmd} >$redirect
+    sleep 5
+
+    # Running test cases through Bottlenecks docker
     if [[ $SUITE_NAME == posca_stress_traffic ]]; then
         TEST_CASE=posca_factor_system_bandwidth
-        echo "Bottlenecks: pulling tutum/influxdb for yardstick"
-        docker pull tutum/influxdb:0.13
-        sleep 5
-        docker exec bottleneckcompose_bottlenecks_1 python ${POSCA_SCRIPT}/run_posca.py testcase $TEST_CASE $REPORT
+        testcase_cmd="docker exec bottlenecks-load-master python ${POSCA_SCRIPT}/../run_testsuite.py testcase $TEST_CASE $REPORT"
+        echo "BOTTLENECKS INFO: running test case ${TEST_CASE} with report indicator: ${testcase_cmd}"
+        ${testcase_cmd} >$redirect
     elif [[ $SUITE_NAME == posca_stress_ping ]]; then
         TEST_CASE=posca_factor_ping
-        sleep 5
-        docker exec bottleneckcompose_bottlenecks_1 python ${POSCA_SCRIPT}/run_posca.py testcase $TEST_CASE $REPORT
+        testcase_cmd="docker exec bottlenecks-load-master python ${POSCA_SCRIPT}/../run_testsuite.py testcase $TEST_CASE $REPORT"
+        echo "BOTTLENECKS INFO: running test case ${TEST_CASE} with report indicator: ${testcase_cmd}"
+        ${testcase_cmd} >$redirect
     fi
-
-    echo "Bottlenecks: cleaning up docker-compose images and dockers"
-    docker-compose -f $WORKSPACE/docker/bottleneck-compose/docker-compose.yml down --rmi all
-fi
\ No newline at end of file
+fi
diff --git a/jjb/calipso/calipso.yml b/jjb/calipso/calipso.yml
new file mode 100644 (file)
index 0000000..c5ba8eb
--- /dev/null
@@ -0,0 +1,61 @@
+- project:
+    name: calipso
+
+    project: '{name}'
+
+    jobs:
+        - 'calipso-verify-{stream}'
+
+    stream:
+        - master:
+            branch: '{stream}'
+            disabled: false
+
+- job-template:
+    name: 'calipso-verify-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - 'opnfv-build-defaults'
+
+
+    scm:
+        - git-scm-gerrit
+
+    triggers:
+        - gerrit:
+            server-name: 'gerrit.opnfv.org'
+            trigger-on:
+                - patchset-created-event:
+                    exclude-drafts: 'false'
+                    exclude-trivial-rebase: 'false'
+                    exclude-no-code-change: 'false'
+                - draft-published-event
+                - comment-added-contains-event:
+                    comment-contains-value: 'recheck'
+                - comment-added-contains-event:
+                    comment-contains-value: 'reverify'
+            projects:
+              - project-compare-type: 'ANT'
+                project-pattern: '{project}'
+                branches:
+                  - branch-compare-type: 'ANT'
+                    branch-pattern: '**/{branch}'
+
+    builders:
+        - verify-unit-tests
+
+- builder:
+    name: verify-unit-tests
+    builders:
+        - shell: |
+            #!/bin/bash
+            set -o errexit
+            set -o nounset
+            set -o pipefail
+            cd $WORKSPACE
+            PYTHONPATH=$PWD/app app/test/verify.sh
index fc3018f..a749d1d 100644 (file)
@@ -12,14 +12,14 @@ if [[ -e securityaudit.log ]] ; then
     if grep ERROR securityaudit.log; then
         EXITSTATUS=1
     fi
-    
-    cat securityaudit.log  | awk -F"ERROR - " '{print $2}' > shortlog
-    
+
+    awk -F"ERROR - " '{print $2}' securityaudit.log | sed -e "s/\"/\\\\\"/g;s/\'/\\\\/g"> shortlog
+
     ssh -p 29418 gerrit.opnfv.org \
         "gerrit review -p $GERRIT_PROJECT \
         -m \"$(cat shortlog)\" \
         $GERRIT_PATCHSET_REVISION \
         --notify NONE"
-    
+
     exit $EXITSTATUS
 fi
index 436a173..1190963 100644 (file)
@@ -15,7 +15,7 @@ source $WORKSPACE/opnfv-projects.sh
 for project in "${PROJECT_LIST[@]}"
 
 do
-  cmd="anteater --project testproj --path /home/opnfv/anteater/allrepos/$project"
+  cmd="/home/opnfv/venv/bin/anteater --project testproj --path /home/opnfv/anteater/allrepos/$project"
   echo "Executing command inside container"
   echo "$cmd"
   echo "--------------------------------------------------------"
index 9bd3cc3..35f9354 100644 (file)
@@ -1,5 +1,7 @@
 #!/bin/bash
 cd $WORKSPACE
+REPORTDIR='.reports'
+mkdir -p $REPORTDIR
 echo "Generating patchset file to list changed files"
 git diff HEAD^1 --name-only | sed "s#^#/home/opnfv/anteater/$PROJECT/#" > $WORKSPACE/patchset
 echo "Changed files are"
@@ -7,7 +9,7 @@ echo "--------------------------------------------------------"
 cat $WORKSPACE/patchset
 echo "--------------------------------------------------------"
 
-vols="-v $WORKSPACE:/home/opnfv/anteater/$PROJECT"
+vols="-v $WORKSPACE:/home/opnfv/anteater/$PROJECT -v $WORKSPACE/$REPORTDIR:/home/opnfv/anteater/$REPORTDIR"
 envs="-e PROJECT=$PROJECT"
 
 echo "Pulling releng-anteater docker image"
index e2f6ceb..3317953 100644 (file)
@@ -1,3 +1,4 @@
+---
 # SPDX-license-identifier: Apache-2.0
 ########################
 # Job configuration for opnfv-anteater (security audit)
     project: anteaterfw
 
     jobs:
-        - 'opnfv-security-audit-verify-{stream}'
-        - 'opnfv-security-audit-weekly-{stream}'
+      - 'opnfv-security-audit-verify-{stream}'
+      - 'opnfv-security-audit-weekly-{stream}'
 
     stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
-            disabled: false
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
 
 ########################
 # job templates
     disabled: '{obj:disabled}'
 
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'ericsson-build3'
-            description: 'Slave label on Jenkins'
-        - project-parameter:
-            project: releng
-            branch: '{branch}'
+      - label:
+          name: SLAVE_LABEL
+          default: 'ericsson-build3'
+          description: 'Slave label on Jenkins'
+      - project-parameter:
+          project: releng
+          branch: '{branch}'
 
     triggers:
-        - timed: '@weekly'
+      - timed: '@weekly'
 
     builders:
-        - anteater-security-audit-weekly
+      - anteater-security-audit-weekly
 
 - job-template:
     name: 'opnfv-security-audit-verify-{stream}'
     disabled: '{obj:disabled}'
 
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'ericsson-build3'
-            description: 'Slave label on Jenkins'
-        - project-parameter:
-            project: $GERRIT_PROJECT
-            branch: '{branch}'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: "Used for overriding the GIT URL coming from Global Jenkins configuration in case if the stuff is done on none-LF HW."
+      - label:
+          name: SLAVE_LABEL
+          default: 'ericsson-build3'
+          description: 'Slave label on Jenkins'
+      - project-parameter:
+          project: $GERRIT_PROJECT
+          branch: '{branch}'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          # yamllint disable rule:line-length
+          description: "Used for overriding the GIT URL coming from Global Jenkins configuration in case if the stuff is done on none-LF HW."
+          # yamllint enable rule:line-length
 
     scm:
-        - git-scm-gerrit
+      - git-scm-gerrit
 
+    # yamllint disable rule:line-length
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - patchset-created-event:
-                    exclude-drafts: 'false'
-                    exclude-trivial-rebase: 'false'
-                    exclude-no-code-change: 'false'
-                - draft-published-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'recheck'
-                - comment-added-contains-event:
-                    comment-contains-value: 'reverify'
-            projects:
-              - project-compare-type: 'REG_EXP'
-                project-pattern: 'apex|armband|bamboo|barometer|bottlenecks|calipso|compass4nfv|conductor|cooper|functest|octopus|pharos|releng|sandbox'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-                file-paths:
-                  - compare-type: ANT
-                    pattern: '**'
-            skip-vote:
-                successful: true
-                failed: true
-                unstable: true
-                notbuilt: true
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: 'recheck'
+            - comment-added-contains-event:
+                comment-contains-value: 'reverify'
+          projects:
+            - project-compare-type: 'REG_EXP'
+              project-pattern: 'apex|armband|bamboo|barometer|bottlenecks|calipso|compass4nfv|conductor|cooper|cperf|daisy|doctor|dovetail|dpacc|enfv|escalator|fds|fuel|functest|octopus|pharos|releng|sandbox|yardstick'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              file-paths:
+                - compare-type: ANT
+                  pattern: '**'
+          skip-vote:
+            successful: true
+            failed: true
+            unstable: true
+            notbuilt: true
+    # yamllint enable rule:line-length
 
     builders:
-        - anteater-security-audit
-        - report-security-audit-result-to-gerrit
+      - anteater-security-audit
+      - report-security-audit-result-to-gerrit
+    publishers:
+      - archive-artifacts:
+          artifacts: ".reports/*"
+
 ########################
 # builder macros
 ########################
 - builder:
     name: anteater-security-audit
     builders:
-        - shell:
-            !include-raw: ./anteater-security-audit.sh
+      - shell:
+          !include-raw: ./anteater-security-audit.sh
 
 - builder:
     name: report-security-audit-result-to-gerrit
     builders:
-        - shell:
-            !include-raw: ./anteater-report-to-gerrit.sh
+      - shell:
+          !include-raw: ./anteater-report-to-gerrit.sh
 
+# yamllint disable rule:indentation
 - builder:
     name: anteater-security-audit-weekly
     builders:
-        - shell:
-            !include-raw:
-                - ./anteater-clone-all-repos.sh
-                - ./anteater-security-audit-weekly.sh
-
+      - shell:
+          !include-raw:
+              - ./anteater-clone-all-repos.sh
+              - ./anteater-security-audit-weekly.sh
+# yamllint enable rule:indentation
index 2472491..8b4a74b 100644 (file)
         stream: master
         branch: '{stream}'
         gs-pathname: ''
+        ppa-pathname: '/{stream}'
         disabled: false
         openstack-version: ocata
     danube: &danube
         stream: danube
         branch: 'stable/{stream}'
         gs-pathname: '/{stream}'
+        ppa-pathname: '/{stream}'
         disabled: false
         openstack-version: newton
 #--------------------------------
         - 'os-nosdn-openo-ha':
             disabled: false
             auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
+        - 'os-odl-sfc-ha':
+            disabled: false
+            auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
+        - 'os-nosdn-dpdk-ha':
+            disabled: false
+            auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
+        - 'k8-nosdn-nofeature-ha':
+            disabled: false
+            auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
+        - 'os-nosdn-nofeature-noha':
+            disabled: false
+            auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
+        - 'os-odl_l3-nofeature-noha':
+            disabled: false
+            auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
+        - 'os-odl_l2-moon-noha':
+            disabled: false
+            auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
+        - 'os-nosdn-kvm-noha':
+            disabled: false
+            auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
+        - 'os-odl-sfc-noha':
+            disabled: false
+            auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
+        - 'os-nosdn-dpdk-noha':
+            disabled: false
+            auto-trigger-name: 'compass-{scenario}-{pod}-{stream}-trigger'
 
 
     jobs:
         - compass-ci-parameter:
             installer: '{installer}'
             gs-pathname: '{gs-pathname}'
+            ppa-pathname: '{ppa-pathname}'
         - string:
             name: DEPLOY_SCENARIO
             default: '{scenario}'
                       WED: true
                       FRI: true
                       SUN: true
+                  use-build-time: true
             steps:
                 - trigger-builds:
-                    - project: 'dovetail-compass-{pod}-proposed_tests-master'
+                    - project: 'dovetail-compass-{pod}-proposed_tests-{stream}'
                       current-parameters: false
-                      predefined-parameters:
+                      predefined-parameters: |
+                        DOCKER_TAG=latest
                         DEPLOY_SCENARIO={scenario}
                       block: true
                       same-node: true
                 - condition-kind: day-of-week
                   day-selector: select-days
                   days:
-                      TUE: true
-                      THU: true
+                      TUES: true
+                      THURS: true
                       SAT: true
+                  use-build-time: true
             steps:
                 - trigger-builds:
-                    - project: 'dovetail-compass-{pod}-proposed_tests-danube'
+                    - project: 'dovetail-compass-{pod}-proposed_tests-{stream}'
                       current-parameters: false
                       predefined-parameters:
                         DEPLOY_SCENARIO={scenario}
             condition-kind: and
             condition-operands:
                 - condition-kind: regex-match
-                  regex: os-(nosdn|odl_l2)-(nofeature|bgpvpn)-ha
+                  regex: os-(nosdn|odl_l2|onos|odl_l3)-nofeature-ha
                   label: '{scenario}'
                 - condition-kind: regex-match
                   regex: master
                   label: '{stream}'
             steps:
                 - trigger-builds:
-                    - project: 'dovetail-compass-{pod}-proposed_tests-master'
+                    - project: 'dovetail-compass-{pod}-proposed_tests-{stream}'
+                      current-parameters: false
+                      predefined-parameters:
+                        DEPLOY_SCENARIO={scenario}
+                      block: true
+                      same-node: true
+                      block-thresholds:
+                        build-step-failure-threshold: 'never'
+                        failure-threshold: 'never'
+                        unstable-threshold: 'FAILURE'
 
 - job-template:
     name: 'compass-deploy-{pod}-daily-{stream}'
         - compass-ci-parameter:
             installer: '{installer}'
             gs-pathname: '{gs-pathname}'
+            ppa-pathname: '{ppa-pathname}'
         - '{slave-label}-defaults'
         - '{installer}-defaults'
 
     builders:
         - description-setter:
             description: "POD: $NODE_NAME"
-        - shell:
-            !include-raw-escape: ./compass-download-artifact.sh
-        - shell:
-            !include-raw-escape: ./compass-deploy.sh
+        - conditional-step:
+            condition-kind: regex-match
+            regex: master
+            label: '{stream}'
+            steps:
+                - shell:
+                    !include-raw-escape: ./compass-build.sh
+                - shell:
+                    !include-raw-escape: ./compass-deploy.sh
+        - conditional-step:
+            condition-kind: regex-match
+            regex: danube
+            label: '{stream}'
+            steps:
+                - shell:
+                    !include-raw-escape: ./compass-download-artifact.sh
+                - shell:
+                    !include-raw-escape: ./compass-deploy.sh
+
 
 ########################
 # parameter macros
             name: GS_URL
             default: '$GS_BASE{gs-pathname}'
             description: "URL to Google Storage."
+        - string:
+            name: CACHE_DIRECTORY
+            default: "$HOME/opnfv/cache/$PROJECT{gs-pathname}"
+            description: "Directory where the cache to be used during the build is located."
+        - string:
+            name: PPA_REPO
+            default: "http://artifacts.opnfv.org/compass4nfv/package{ppa-pathname}"
+        - string:
+            name: PPA_CACHE
+            default: "$WORKSPACE/work/repo/"
 
 ########################
 # trigger macros
 ########################
+
+#---------------------------
+# ha-baremetal-centos-master
+#---------------------------
 - trigger:
     name: 'compass-os-nosdn-nofeature-ha-baremetal-centos-master-trigger'
     triggers:
 - trigger:
     name: 'compass-os-odl_l2-nofeature-ha-baremetal-centos-master-trigger'
     triggers:
-        - timed: '0 23 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-odl_l3-nofeature-ha-baremetal-centos-master-trigger'
     triggers:
 - trigger:
     name: 'compass-os-onos-nofeature-ha-baremetal-centos-master-trigger'
     triggers:
-        - timed: '0 7 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-ocl-nofeature-ha-baremetal-centos-master-trigger'
     triggers:
-        - timed: '0 11 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-onos-sfc-ha-baremetal-centos-master-trigger'
     triggers:
-        - timed: '0 3 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-odl_l2-moon-ha-baremetal-centos-master-trigger'
     triggers:
     name: 'compass-os-nosdn-kvm-ha-baremetal-centos-master-trigger'
     triggers:
         - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-dpdk-ha-baremetal-centos-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl-sfc-ha-baremetal-centos-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-k8-nosdn-nofeature-ha-baremetal-centos-master-trigger'
+    triggers:
+        - timed: ''
+
+#-----------------------------
+# noha-baremetal-centos-master
+#-----------------------------
+- trigger:
+    name: 'compass-os-nosdn-nofeature-noha-baremetal-centos-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl_l3-nofeature-noha-baremetal-centos-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl_l2-moon-noha-baremetal-centos-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-kvm-noha-baremetal-centos-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl-sfc-noha-baremetal-centos-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-dpdk-noha-baremetal-centos-master-trigger'
+    triggers:
+        - timed: ''
 
+#--------------------
+# ha-baremetal-master
+#--------------------
 - trigger:
     name: 'compass-os-nosdn-nofeature-ha-baremetal-master-trigger'
     triggers:
-        - timed: '0 2 * * *'
+        - timed: '0 20 * * *'
 - trigger:
     name: 'compass-os-nosdn-openo-ha-baremetal-master-trigger'
     triggers:
-        - timed: '0 3 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-odl_l2-nofeature-ha-baremetal-master-trigger'
     triggers:
-        - timed: '0 22 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-odl_l3-nofeature-ha-baremetal-master-trigger'
     triggers:
 - trigger:
     name: 'compass-os-onos-nofeature-ha-baremetal-master-trigger'
     triggers:
-        - timed: '0 14 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-ocl-nofeature-ha-baremetal-master-trigger'
     triggers:
-        - timed: '0 10 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-onos-sfc-ha-baremetal-master-trigger'
     triggers:
-        - timed: '0 6 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-odl_l2-moon-ha-baremetal-master-trigger'
     triggers:
-        - timed: ''
+        - timed: '0 12 * * *'
 - trigger:
     name: 'compass-os-nosdn-kvm-ha-baremetal-master-trigger'
+    triggers:
+        - timed: '0 14 * * *'
+- trigger:
+    name: 'compass-os-nosdn-dpdk-ha-baremetal-master-trigger'
+    triggers:
+        - timed: '0 16 * * *'
+- trigger:
+    name: 'compass-k8-nosdn-nofeature-ha-baremetal-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl-sfc-ha-baremetal-master-trigger'
+    triggers:
+        - timed: '0 10 * * *'
+
+#----------------------
+# noha-baremetal-master
+#----------------------
+- trigger:
+    name: 'compass-os-nosdn-kvm-noha-baremetal-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-nofeature-noha-baremetal-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl_l3-nofeature-noha-baremetal-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl_l2-moon-noha-baremetal-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl-sfc-noha-baremetal-master-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-dpdk-noha-baremetal-master-trigger'
     triggers:
         - timed: ''
 
+#--------------------
+# ha-baremetal-danube
+#--------------------
 - trigger:
     name: 'compass-os-nosdn-nofeature-ha-baremetal-danube-trigger'
     triggers:
     name: 'compass-os-nosdn-kvm-ha-baremetal-danube-trigger'
     triggers:
         - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-dpdk-ha-baremetal-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-k8-nosdn-nofeature-ha-baremetal-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl-sfc-ha-baremetal-danube-trigger'
+    triggers:
+        - timed: ''
 
+#----------------------
+# noha-baremetal-danube
+#----------------------
+- trigger:
+    name: 'compass-os-nosdn-kvm-noha-baremetal-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-nofeature-noha-baremetal-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl_l3-nofeature-noha-baremetal-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl_l2-moon-noha-baremetal-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl-sfc-noha-baremetal-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-dpdk-noha-baremetal-danube-trigger'
+    triggers:
+        - timed: ''
+
+#------------------
+# ha-virtual-master
+#------------------
 - trigger:
     name: 'compass-os-nosdn-nofeature-ha-virtual-master-trigger'
     triggers:
 - trigger:
     name: 'compass-os-nosdn-openo-ha-virtual-master-trigger'
     triggers:
-        - timed: '0 22 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-odl_l2-nofeature-ha-virtual-master-trigger'
     triggers:
-        - timed: '0 20 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-odl_l3-nofeature-ha-virtual-master-trigger'
     triggers:
 - trigger:
     name: 'compass-os-onos-nofeature-ha-virtual-master-trigger'
     triggers:
-        - timed: '0 18 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-ocl-nofeature-ha-virtual-master-trigger'
     triggers:
-        - timed: '0 16 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-onos-sfc-ha-virtual-master-trigger'
     triggers:
-        - timed: '0 15 * * *'
+        - timed: ''
 - trigger:
     name: 'compass-os-odl_l2-moon-ha-virtual-master-trigger'
     triggers:
-        - timed: '0 14 * * *'
+        - timed: '0 12 * * *'
 - trigger:
     name: 'compass-os-nosdn-kvm-ha-virtual-master-trigger'
+    triggers:
+        - timed: '0 13 * * *'
+- trigger:
+    name: 'compass-os-nosdn-dpdk-ha-virtual-master-trigger'
+    triggers:
+        - timed: '0 17 * * *'
+- trigger:
+    name: 'compass-k8-nosdn-nofeature-ha-virtual-master-trigger'
     triggers:
         - timed: ''
+- trigger:
+    name: 'compass-os-odl-sfc-ha-virtual-master-trigger'
+    triggers:
+        - timed: '0 16 * * *'
+
+#--------------------
+# noha-virtual-master
+#--------------------
+- trigger:
+    name: 'compass-os-nosdn-kvm-noha-virtual-master-trigger'
+    triggers:
+        - timed: '0 13 * * *'
+- trigger:
+    name: 'compass-os-nosdn-nofeature-noha-virtual-master-trigger'
+    triggers:
+        - timed: '0 14 * * *'
+- trigger:
+    name: 'compass-os-odl_l3-nofeature-noha-virtual-master-trigger'
+    triggers:
+        - timed: '0 15 * * *'
+- trigger:
+    name: 'compass-os-odl_l2-moon-noha-virtual-master-trigger'
+    triggers:
+        - timed: '0 18 * * *'
+- trigger:
+    name: 'compass-os-odl-sfc-noha-virtual-master-trigger'
+    triggers:
+        - timed: '0 20 * * *'
+- trigger:
+    name: 'compass-os-nosdn-dpdk-noha-virtual-master-trigger'
+    triggers:
+        - timed: '0 11 * * *'
 
+#------------------
+# ha-virtual-danube
+#------------------
 - trigger:
     name: 'compass-os-nosdn-nofeature-ha-virtual-danube-trigger'
     triggers:
     name: 'compass-os-nosdn-kvm-ha-virtual-danube-trigger'
     triggers:
         - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-dpdk-ha-virtual-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl-sfc-ha-virtual-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-k8-nosdn-nofeature-ha-virtual-danube-trigger'
+    triggers:
+        - timed: ''
+
+#--------------------
+# noha-virtual-danube
+#--------------------
+- trigger:
+    name: 'compass-os-nosdn-kvm-noha-virtual-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-nofeature-noha-virtual-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl_l3-nofeature-noha-virtual-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl_l2-moon-noha-virtual-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-odl-sfc-noha-virtual-danube-trigger'
+    triggers:
+        - timed: ''
+- trigger:
+    name: 'compass-os-nosdn-dpdk-noha-virtual-danube-trigger'
+    triggers:
+        - timed: ''
index 2668ccd..9d4ae51 100644 (file)
@@ -6,24 +6,23 @@ echo "Starting the deployment on baremetal environment using $INSTALLER_TYPE. Th
 echo "--------------------------------------------------------"
 echo
 
-# source the properties file so we get OPNFV vars
-source $BUILD_DIRECTORY/latest.properties
-
-# echo the info about artifact that is used during the deployment
-echo "Using ${OPNFV_ARTIFACT_URL/*\/} for deployment"
-
-if [[ ! "$JOB_NAME" =~ (verify|merge) ]]; then
-    # for none-merge deployments
-    # checkout the commit that was used for building the downloaded artifact
-    # to make sure the ISO and deployment mechanism uses same versions
-    echo "Checking out $OPNFV_GIT_SHA1"
-    git checkout $OPNFV_GIT_SHA1 --quiet
-fi
-
 echo 1 > /proc/sys/vm/drop_caches
 
 export CONFDIR=$WORKSPACE/deploy/conf
 if [[ "$BRANCH" = 'stable/danube' ]]; then
+    # source the properties file so we get OPNFV vars
+    source $BUILD_DIRECTORY/latest.properties
+    # echo the info about artifact that is used during the deployment
+    echo "Using ${OPNFV_ARTIFACT_URL/*\/} for deployment"
+
+    if [[ ! "$JOB_NAME" =~ (verify|merge) ]]; then
+        # for none-merge deployments
+        # checkout the commit that was used for building the downloaded artifact
+        # to make sure the ISO and deployment mechanism uses same versions
+        echo "Checking out $OPNFV_GIT_SHA1"
+        git checkout $OPNFV_GIT_SHA1 --quiet
+    fi
+
     export ISO_URL=file://$BUILD_DIRECTORY/compass.iso
 else
     export ISO_URL=file://$BUILD_DIRECTORY/compass.tar.gz
@@ -40,6 +39,8 @@ elif [[ "${DEPLOY_SCENARIO}" =~ "-onos" ]]; then
     export NETWORK_CONF_FILE=network_onos.yml
 elif [[ "${DEPLOY_SCENARIO}" =~ "-openo" ]]; then
     export NETWORK_CONF_FILE=network_openo.yml
+elif [[ "${DEPLOY_SCENARIO}" =~ "-dpdk" ]]; then
+    export NETWORK_CONF_FILE=network_dpdk.yml
 else
     export NETWORK_CONF_FILE=network.yml
 fi
@@ -51,6 +52,11 @@ fi
 if [[ "$NODE_NAME" =~ "-virtual" ]]; then
     export NETWORK_CONF=$CONFDIR/vm_environment/$NODE_NAME/${NETWORK_CONF_FILE}
     export DHA_CONF=$CONFDIR/vm_environment/${DEPLOY_SCENARIO}.yml
+    if [[ "${DEPLOY_SCENARIO}" =~ "-moon-noha" ]]; then
+        export VIRT_NUMBER=3
+    elif [[ "${DEPLOY_SCENARIO}" =~ "-noha" ]]; then
+        export VIRT_NUMBER=2
+    fi
 else
     export INSTALL_NIC=eth1
     export NETWORK_CONF=$CONFDIR/hardware_environment/$NODE_NAME/${NETWORK_CONF_FILE}
index 67d1e4e..101db82 100644 (file)
@@ -19,7 +19,7 @@
 #------------------------------------
     pod:
         - baremetal:
-            slave-label: compass-baremetal
+            slave-label: compass-baremetal-branch
             os-version: 'xenial'
             <<: *danube
 #-----------------------------------
index 5948245..e612ef6 100644 (file)
             disabled: false
 
     jobs:
-        - 'compass-build-iso-{stream}'
+        - '{installer}-build-daily-{stream}'
         - 'compass-build-ppa-{stream}'
 
 ########################
 # job templates
 ########################
 - job-template:
-    name: 'compass-build-iso-{stream}'
+    name: '{installer}-build-daily-{stream}'
 
     disabled: '{obj:disabled}'
 
@@ -64,8 +64,7 @@
             !include-raw-escape: ./compass-build.sh
         - shell:
             !include-raw-escape: ./compass-upload-artifact.sh
-        - shell:
-            !include-raw-escape: ./compass-workspace-cleanup.sh
+        - 'clean-workspace'
 
 - job-template:
     name: 'compass-build-ppa-{stream}'
index e43f976..ee91e02 100644 (file)
@@ -29,7 +29,7 @@
             os-version: 'xenial'
             openstack-os-version: ''
         - 'centos7':
-            disabled: false
+            disabled: true
             os-version: 'centos7'
             openstack-os-version: ''
 #####################################
             condition: SUCCESSFUL
             projects:
                 - name: 'functest-compass-virtual-suite-{stream}'
-                  current-parameters: true
-                  predefined-parameters:
+                  current-parameters: false
+                  predefined-parameters: |
                     FUNCTEST_SUITE_NAME=healthcheck
+                    DEPLOY_SCENARIO=os-nosdn-nofeature-ha
                   node-parameters: true
                   kill-phase-on: NEVER
                   abort-all-job: true
                 - name: 'functest-compass-virtual-suite-{stream}'
-                  current-parameters: true
-                  predefined-parameters:
+                  current-parameters: false
+                  predefined-parameters: |
                     FUNCTEST_SUITE_NAME=vping_ssh
+                    DEPLOY_SCENARIO=os-nosdn-nofeature-ha
                   node-parameters: true
                   kill-phase-on: NEVER
                   abort-all-job: true
diff --git a/jjb/compass4nfv/compass-workspace-cleanup.sh b/jjb/compass4nfv/compass-workspace-cleanup.sh
deleted file mode 100644 (file)
index 98201af..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-set -o errexit
-set -o nounset
-set -o pipefail
-
-# delete everything that is in $WORKSPACE
-/bin/rm -rf $WORKSPACE
\ No newline at end of file
similarity index 94%
rename from jjb/openretriever/openretriever-project.yml
rename to jjb/container4nfv/container4nfv-project.yml
index 3bcfab6..3b29b36 100644 (file)
@@ -3,12 +3,12 @@
 # They will only be enabled on request by projects!
 ###################################################
 - project:
-    name: openretriever
+    name: container4nfv
 
     project: '{name}'
 
     jobs:
-        - 'openretriever-verify-{stream}'
+        - 'container4nfv-verify-{stream}'
 
     stream:
         - master:
@@ -21,7 +21,7 @@
             disabled: false
 
 - job-template:
-    name: 'openretriever-verify-{stream}'
+    name: 'container4nfv-verify-{stream}'
 
     disabled: '{obj:disabled}'
 
index dc209d6..fdd3509 100644 (file)
@@ -1,3 +1,4 @@
+---
 ###################################
 # job configuration for cperf
 ###################################
@@ -5,40 +6,39 @@
     name: cperf-ci-jobs
     project: cperf
 
-#--------------------------------
-# BRANCH ANCHORS
-#--------------------------------
+    # -------------------------------
+    # BRANCH ANCHORS
+    # -------------------------------
     master: &master
-        stream: master
-        branch: '{stream}'
-        gs-pathname: ''
-        docker-tag: 'latest'
+      stream: master
+      branch: '{stream}'
+      gs-pathname: ''
+      docker-tag: 'latest'
     danube: &danube
-        stream: danube
-        branch: 'stable/{stream}'
-        gs-pathname: '/{stream}'
-        docker-tag: 'stable'
-
-#--------------------------------
-# POD, INSTALLER, AND BRANCH MAPPING
-#--------------------------------
+      stream: danube
+      branch: 'stable/{stream}'
+      gs-pathname: '/{stream}'
+      docker-tag: 'stable'
+
+    # -------------------------------
+    # POD, INSTALLER, AND BRANCH MAPPING
+    # -------------------------------
     pod:
-#--------------------------------
-#        master
-#--------------------------------
-        - intel-pod2:
-            installer: apex
-            <<: *master
-        - intel-pod2:
-            installer: apex
-            <<: *danube
-#--------------------------------
+      # -------------------------------
+      #        master
+      # -------------------------------
+      - intel-pod2:
+          installer: apex
+          <<: *master
+      - intel-pod2:
+          installer: apex
+          <<: *danube
 
     testsuite:
-        - 'daily'
+      - 'daily'
 
     jobs:
-        - 'cperf-{installer}-{pod}-{testsuite}-{stream}'
+      - 'cperf-{installer}-{pod}-{testsuite}-{stream}'
 
 ################################
 # job template
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-per-node: 1
-            option: 'project'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-per-node: 1
+          option: 'project'
 
     wrappers:
-        - build-name:
-            name: '$BUILD_NUMBER Suite: $CPERF_SUITE_NAME Scenario: $DEPLOY_SCENARIO'
-        - timeout:
-            timeout: 400
-            abort: true
+      - build-name:
+          name: '$BUILD_NUMBER Suite: $CPERF_SUITE_NAME Scenario: $DEPLOY_SCENARIO'
+      - timeout:
+          timeout: 400
+          abort: true
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - '{pod}-defaults'
-        - '{installer}-defaults'
-        - cperf-parameter:
-            testsuite: '{testsuite}'
-            gs-pathname: '{gs-pathname}'
-            docker-tag: '{docker-tag}'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - '{pod}-defaults'
+      - '{installer}-defaults'
+      - cperf-parameter:
+          testsuite: '{testsuite}'
+          gs-pathname: '{gs-pathname}'
+          docker-tag: '{docker-tag}'
 
     scm:
-        - git-scm
+      - git-scm
 
     builders:
-        - 'cperf-{testsuite}-builder'
+      - 'cperf-{testsuite}-builder'
 
 ########################
 # parameter macros
 - parameter:
     name: cperf-parameter
     parameters:
-        - string:
-            name: CPERF_SUITE_NAME
-            default: '{testsuite}'
-            description: "Suite name to run"
-        - string:
-            name: GS_PATHNAME
-            default: '{gs-pathname}'
-            description: "Version directory where the opnfv documents will be stored in gs repository"
-        - string:
-            name: CI_DEBUG
-            default: 'false'
-            description: "Show debug output information"
-        - string:
-            name: DOCKER_TAG
-            default: '{docker-tag}'
-            description: 'Tag to pull docker image'
+      - string:
+          name: CPERF_SUITE_NAME
+          default: '{testsuite}'
+          description: "Suite name to run"
+      - string:
+          name: GS_PATHNAME
+          default: '{gs-pathname}'
+          description: "Version directory where the opnfv documents will be stored in gs repository"
+      - string:
+          name: CI_DEBUG
+          default: 'false'
+          description: "Show debug output information"
+      - string:
+          name: DOCKER_TAG
+          default: '{docker-tag}'
+          description: 'Tag to pull docker image'
 
 ########################
 # trigger macros
 - builder:
     name: cperf-daily-builder
     builders:
-        - 'cperf-cleanup'
-        - 'cperf-robot-cbench'
+      - 'cperf-cleanup'
+      - 'cperf-robot-cbench'
 
 - builder:
     name: cperf-robot-cbench
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o nounset
-            set -o pipefail
-            undercloud_mac=$(sudo virsh domiflist undercloud | grep default | \
-                              grep -Eo "[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+")
-            INSTALLER_IP=$(/usr/sbin/arp -e | grep ${undercloud_mac} | awk {'print $1'})
-
-            sudo scp -o StrictHostKeyChecking=no root@$INSTALLER_IP:/home/stack/overcloudrc /tmp/overcloudrc
-            sudo chmod 755 /tmp/overcloudrc
-            source /tmp/overcloudrc
-
-            # robot suites need the ssh key to log in to controller nodes, so throwing it
-            # in tmp, and mounting /tmp as $HOME as far as robot is concerned
-            sudo rm -rf /tmp/.ssh
-            sudo mkdir /tmp/.ssh
-            sudo chmod 0700 /tmp/.ssh
-            sudo scp -o StrictHostKeyChecking=no root@$INSTALLER_IP:/home/stack/.ssh/id_rsa /tmp/.ssh/
-            sudo chown -R jenkins-ci:jenkins-ci /tmp/.ssh
-            # done with sudo. jenkins-ci is the user from this point
-            chmod 0600 /tmp/.ssh/id_rsa
-
-            # cbench requires the openflow drop test feature to be installed.
-            sshpass -p karaf ssh -o StrictHostKeyChecking=no \
-                                 -o UserKnownHostsFile=/dev/null \
-                                 -o LogLevel=error \
-                                 -p 8101 karaf@$SDN_CONTROLLER_IP \
-                                  feature:install odl-openflowplugin-flow-services-ui odl-openflowplugin-drop-test
-
-            docker pull opnfv/cperf:$DOCKER_TAG
-
-            robot_cmd="pybot -e exclude -L TRACE -d /tmp \
-                        -v ODL_SYSTEM_1_IP:${SDN_CONTROLLER_IP} \
-                        -v ODL_SYSTEM_IP:${SDN_CONTROLLER_IP} \
-                        -v BUNDLEFOLDER:/opt/opendaylight \
-                        -v RESTCONFPORT:8081 \
-                        -v USER_HOME:/tmp \
-                        -v USER:heat-admin \
-                        -v ODL_SYSTEM_USER:heat-admin \
-                        -v TOOLS_SYSTEM_IP:localhost \
-                        -v of_port:6653"
-            robot_suite="/home/opnfv/repos/odl_test/csit/suites/openflowplugin/Performance/010_Cbench.robot"
-
-            docker run -i -v /tmp:/tmp opnfv/cperf:$DOCKER_TAG ${robot_cmd} ${robot_suite}
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o nounset
+          set -o pipefail
+          undercloud_mac=$(sudo virsh domiflist undercloud | grep default | \
+                            grep -Eo "[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+")
+          INSTALLER_IP=$(/usr/sbin/arp -e | grep ${undercloud_mac} | awk {'print $1'})
+
+          sudo scp -o StrictHostKeyChecking=no root@$INSTALLER_IP:/home/stack/overcloudrc /tmp/overcloudrc
+          sudo chmod 755 /tmp/overcloudrc
+          source /tmp/overcloudrc
+
+          # robot suites need the ssh key to log in to controller nodes, so throwing it
+          # in tmp, and mounting /tmp as $HOME as far as robot is concerned
+          sudo rm -rf /tmp/.ssh
+          sudo mkdir /tmp/.ssh
+          sudo chmod 0700 /tmp/.ssh
+          sudo scp -o StrictHostKeyChecking=no root@$INSTALLER_IP:/home/stack/.ssh/id_rsa /tmp/.ssh/
+          sudo chown -R jenkins-ci:jenkins-ci /tmp/.ssh
+          # done with sudo. jenkins-ci is the user from this point
+          chmod 0600 /tmp/.ssh/id_rsa
+
+          # cbench requires the openflow drop test feature to be installed.
+          sshpass -p karaf ssh -o StrictHostKeyChecking=no \
+                               -o UserKnownHostsFile=/dev/null \
+                               -o LogLevel=error \
+                               -p 8101 karaf@$SDN_CONTROLLER_IP \
+                                feature:install odl-openflowplugin-flow-services-ui odl-openflowplugin-drop-test
+
+          docker pull opnfv/cperf:$DOCKER_TAG
+
+          robot_cmd="pybot -e exclude -L TRACE -d /tmp \
+                      -v ODL_SYSTEM_1_IP:${SDN_CONTROLLER_IP} \
+                      -v ODL_SYSTEM_IP:${SDN_CONTROLLER_IP} \
+                      -v BUNDLEFOLDER:/opt/opendaylight \
+                      -v RESTCONFPORT:8081 \
+                      -v USER_HOME:/tmp \
+                      -v USER:heat-admin \
+                      -v ODL_SYSTEM_USER:heat-admin \
+                      -v TOOLS_SYSTEM_IP:localhost \
+                      -v of_port:6653"
+          robot_suite="/home/opnfv/repos/odl_test/csit/suites/openflowplugin/Performance/010_Cbench.robot"
+
+          docker run -i -v /tmp:/tmp opnfv/cperf:$DOCKER_TAG ${robot_cmd} ${robot_suite}
 
 - builder:
     name: cperf-cleanup
     builders:
-        - shell: |
-            #!/bin/bash
-            [[ $CI_DEBUG == true ]] && redirect="/dev/stdout" || redirect="/dev/null"
-
-            echo "Cleaning up docker containers/images..."
-            # Remove previous running containers if exist
-            if [[ ! -z $(docker ps -a | grep opnfv/cperf) ]]; then
-                echo "Removing existing opnfv/cperf containers..."
-                docker ps -a | grep opnfv/cperf | awk '{print $1}' | xargs docker rm -f >${redirect}
-            fi
-
-            # Remove existing images if exist
-            if [[ ! -z $(docker images | grep opnfv/cperf) ]]; then
-                echo "Docker images to remove:"
-                docker images | head -1 && docker images | grep opnfv/cperf >${redirect}
-                image_tags=($(docker images | grep opnfv/cperf | awk '{print $2}'))
-                for tag in "${image_tags[@]}"; do
-                    echo "Removing docker image opnfv/cperf:$tag..."
-                    docker rmi opnfv/cperf:$tag >/dev/null
-                done
-            fi
+      - shell: |
+          #!/bin/bash
+          [[ $CI_DEBUG == true ]] && redirect="/dev/stdout" || redirect="/dev/null"
+
+          echo "Cleaning up docker containers/images..."
+          # Remove previous running containers if exist
+          if [[ ! -z $(docker ps -a | grep opnfv/cperf) ]]; then
+              echo "Removing existing opnfv/cperf containers..."
+              docker ps -a | grep opnfv/cperf | awk '{print $1}' | xargs docker rm -f >${redirect}
+          fi
+
+          # Remove existing images if exist
+          if [[ ! -z $(docker images | grep opnfv/cperf) ]]; then
+              echo "Docker images to remove:"
+              docker images | head -1 && docker images | grep opnfv/cperf >${redirect}
+              image_tags=($(docker images | grep opnfv/cperf | awk '{print $2}'))
+              for tag in "${image_tags[@]}"; do
+                  echo "Removing docker image opnfv/cperf:$tag..."
+                  docker rmi opnfv/cperf:$tag >/dev/null
+              done
+          fi
index aac76ba..9a680e7 100644 (file)
@@ -45,6 +45,9 @@
         # NOHA scenarios
         - 'os-nosdn-nofeature-noha':
             auto-trigger-name: 'daisy-{scenario}-{pod}-daily-{stream}-trigger'
+        # ODL_L3 scenarios
+        - 'os-odl-nofeature-ha':
+            auto-trigger-name: 'daisy-{scenario}-{pod}-daily-{stream}-trigger'
 
     jobs:
         - '{project}-{scenario}-{pod}-daily-{stream}'
 #-----------------------------------------------
 # Triggers for job running on daisy-baremetal against master branch
 #-----------------------------------------------
-# HA Scenarios
+# Basic HA Scenarios
 - trigger:
     name: 'daisy-os-nosdn-nofeature-ha-baremetal-daily-master-trigger'
     triggers:
-        - timed: ''
-# NOHA Scenarios
+        - timed: '0 16 * * *'
+# Basic NOHA Scenarios
 - trigger:
     name: 'daisy-os-nosdn-nofeature-noha-baremetal-daily-master-trigger'
     triggers:
         - timed: ''
+# ODL Scenarios
+- trigger:
+    name: 'daisy-os-odl-nofeature-ha-baremetal-daily-master-trigger'
+    triggers:
+        - timed: '0 12 * * *'
 #-----------------------------------------------
 # Triggers for job running on daisy-virtual against master branch
 #-----------------------------------------------
+# Basic HA Scenarios
 - trigger:
     name: 'daisy-os-nosdn-nofeature-ha-virtual-daily-master-trigger'
     triggers:
-        - timed: ''
-# NOHA Scenarios
+        - timed: '0 16 * * *'
+# Basic NOHA Scenarios
 - trigger:
     name: 'daisy-os-nosdn-nofeature-noha-virtual-daily-master-trigger'
     triggers:
-        - timed: 'H 8,22 * * *'
-
+        - timed: ''
+# ODL Scenarios
+- trigger:
+    name: 'daisy-os-odl-nofeature-ha-virtual-daily-master-trigger'
+    triggers:
+        - timed: '0 12 * * *'
index 785f3a5..0bcac4b 100755 (executable)
@@ -28,7 +28,7 @@ git clone ssh://jenkins-zte@gerrit.opnfv.org:29418/securedlab --quiet \
 # daisy ci/deploy/deploy.sh use $BASE_DIR/labs dir
 cp -r securedlab/labs .
 
-DEPLOY_COMMAND="sudo ./ci/deploy/deploy.sh -b $BASE_DIR \
+DEPLOY_COMMAND="sudo -E ./ci/deploy/deploy.sh -b $BASE_DIR \
                 -l $LAB_NAME -p $POD_NAME -B $BRIDGE -s $DEPLOY_SCENARIO"
 
 # log info to console
index 0a9d43d..bcb8910 100644 (file)
             branch: '{stream}'
             gs-pathname: ''
             disabled: false
-        - danube:
-            branch: 'stable/{stream}'
-            gs-pathname: '/{stream}'
-            disabled: false
 
     phase:
         - 'build':
             use-build-blocker: true
             blocking-jobs:
                 - '{installer}-daily-.*'
+                - 'daisy4nfv-merge-build-.*'
+                - 'daisy4nfv-verify-build-.*'
             block-level: 'NODE'
 
     scm:
         - git-scm
 
     triggers:
-        - timed: '0 H/8 * * *'
+        - timed: '0 8 * * *'
 
     parameters:
         - project-parameter:
 
     publishers:
         - '{installer}-recipients'
+        - email-jenkins-admins-on-failure
 
 - job-template:
     name: '{installer}-{phase}-daily-{stream}'
             !include-raw: ./daisy4nfv-build.sh
         - shell:
             !include-raw: ./daisy4nfv-upload-artifact.sh
-        - shell:
-            !include-raw: ./daisy4nfv-workspace-cleanup.sh
+        - 'clean-workspace'
 
 - builder:
     name: 'daisy-deploy-daily-macro'
     publishers:
         - email:
             recipients: hu.zhijiang@zte.com.cn lu.yao135@zte.com.cn zhou.ya@zte.com.cn yangyang1@zte.com.cn julienjut@gmail.com
+        - email-jenkins-admins-on-failure
 
 - parameter:
     name: 'daisy-project-parameter'
index 561ffbe..97d830f 100644 (file)
             use-build-blocker: true
             blocking-jobs:
                 - '{alias}-merge-{phase}-.*'
+                - '{installer}-daily-.*'
             block-level: 'NODE'
 
     scm:
             !include-raw: ./daisy4nfv-build.sh
         - shell:
             !include-raw: ./daisy4nfv-upload-artifact.sh
-        - shell:
-            !include-raw: ./daisy4nfv-workspace-cleanup.sh
+        - 'clean-workspace'
 
 - builder:
     name: 'daisy-merge-deploy-virtual-macro'
             !include-raw: ./daisy4nfv-download-artifact.sh
         - shell:
             !include-raw: ./daisy-deploy.sh
-        - shell:
-            !include-raw: ./daisy4nfv-workspace-cleanup.sh
+        - 'clean-workspace'
 
 #####################################
 # parameter macros
index dff0ff0..1828ce4 100644 (file)
@@ -50,7 +50,7 @@
         - build-blocker:
             use-build-blocker: true
             blocking-jobs:
-                - '{installer}-merge-build-.*'
+                - '{alias}-merge-build-.*'
             block-level: 'NODE'
 
     scm:
         - build-blocker:
             use-build-blocker: true
             blocking-jobs:
-                - '{installer}-merge-build-.*'
+                - '{alias}-merge-build-.*'
                 - '{alias}-verify-build-.*'
+                - '{installer}-daily-.*'
             block-level: 'NODE'
 
     scm:
             !include-raw: ./daisy4nfv-basic.sh
         - shell:
             !include-raw: ./daisy4nfv-build.sh
-        - shell:
-            !include-raw: ./daisy4nfv-workspace-cleanup.sh
+        - 'clean-workspace'
 
 - builder:
     name: daisy-verify-unit-macro
diff --git a/jjb/daisy4nfv/daisy4nfv-workspace-cleanup.sh b/jjb/daisy4nfv/daisy4nfv-workspace-cleanup.sh
deleted file mode 100755 (executable)
index 26f7e9a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-##############################################################################
-# Copyright (c) 2016 ZTE Coreporation and others.
-# hu.zhijiang@zte.com.cn
-# sun.jing22@zte.com.cn
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o errexit
-set -o nounset
-set -o pipefail
-
-# delete the $WORKSPACE to open some space
-/bin/rm -rf $WORKSPACE
index 5a438e4..b007e14 100644 (file)
 
     installer:
         - apex:
-            slave-label: 'ool-virtual1'
-            pod: 'ool-virtual1'
+            slave-label: 'doctor-apex-verify'
         - fuel:
-            slave-label: 'ool-virtual2'
-            pod: 'ool-virtual2'
+            slave-label: 'doctor-fuel-verify'
         #- joid:
         #    slave-label: 'ool-virtual3'
         #    pod: 'ool-virtual3'
 
     task:
         - verify:
-            profiler: 'none'
             auto-trigger-name: 'doctor-verify'
             is-python: false
-        - profiling:
-            profiler: 'poc'
-            auto-trigger-name: 'experimental'
-            is-python: false
         - python-verify:
-            profiler: 'none'
             auto-trigger-name: 'doctor-verify'
             is-python: true
 
     pod:
-        - arm-pod2:
+        - armband-baremetal:
             slave-label: '{pod}'
-        - arm-pod3:
+        - armband-virtual:
             slave-label: '{pod}'
 
     jobs:
         - '{auto-trigger-name}':
             project: '{project}'
             branch: '{branch}'
+            files: 'tests/**'
 
     builders:
         - shell: "[ -e tests/run.sh ] && bash -n ./tests/run.sh"
             default: 'doctor-notification'
         - string:
             name: TESTCASE_OPTIONS
-            default: '-e INSPECTOR_TYPE={inspector} -e PROFILER_TYPE={profiler} -e PYTHON_ENABLE={is-python} -v $WORKSPACE:/home/opnfv/repos/doctor'
+            default: '-e INSPECTOR_TYPE={inspector} -e PYTHON_ENABLE={is-python} -v $WORKSPACE:/home/opnfv/repos/doctor'
             description: 'Addtional parameters specific to test case(s)'
         # functest-parameter
         - string:
         - '{auto-trigger-name}':
             project: '{project}'
             branch: '{branch}'
+            files: 'tests/**'
 
     builders:
         - 'clean-workspace-log'
             #       so this symbolic link should not be in 'tests/'. Otherwise,
             #       we'll have the same log twice in jenkins console log.
             ln -sfn $HOME/opnfv/functest/results/{stream} functest_results
+            # NOTE: Get functest script in $WORKSPACE. This functest script is
+            #       needed to perform VM image download in set-functest-env.sh
+            #       from E release cycle.
+            mkdir -p functest/ci
+            wget https://git.opnfv.org/functest/plain/functest/ci/download_images.sh -O functest/ci/download_images.sh
         - 'functest-suite-builder'
         - shell: |
-            functest_log="$HOME/opnfv/functest/results/{stream}/{project}.log"
+            functest_log="$HOME/opnfv/functest/results/{stream}/$FUNCTEST_SUITE_NAME.log"
             # NOTE: checking the test result, as the previous job could return
             #       0 regardless the result of doctor test scenario.
             grep -e ' OK$' $functest_log || exit 1
         - archive:
             artifacts: 'tests/*.log'
         - archive:
-            artifacts: 'functest_results/{project}.log'
+            artifacts: 'functest_results/$FUNCTEST_SUITE_NAME.log'
+        - email-jenkins-admins-on-failure
 
 
 #####################################
                     branch-pattern: '**/{branch}'
                 file-paths:
                   - compare-type: ANT
-                    pattern: 'tests/**'
+                    pattern: '{files}'
             skip-vote:
                 successful: true
                 failed: true
index 6bcaea2..938fdf9 100644 (file)
@@ -25,7 +25,7 @@
         branch: 'stable/{stream}'
         dovetail-branch: master
         gs-pathname: '/{stream}'
-        docker-tag: 'cvp.0.1.0'
+        docker-tag: 'cvp.0.6.0'
 
 #-----------------------------------
 # POD, PLATFORM, AND BRANCH MAPPING
 # that have not been switched using labels for slaves
 #--------------------------------
 #apex PODs
-        - lf-pod1:
-            slave-label: '{pod}'
+        - virtual:
+            slave-label: apex-virtual-master
             SUT: apex
             auto-trigger-name: 'daily-trigger-disabled'
             <<: *master
-        - lf-pod1:
-            slave-label: '{pod}'
+        - baremetal:
+            slave-label: apex-baremetal-master
+            SUT: apex
+            auto-trigger-name: 'daily-trigger-disabled'
+            <<: *master
+        - virtual:
+            slave-label: apex-virtual-danube
+            SUT: apex
+            auto-trigger-name: 'daily-trigger-disabled'
+            <<: *danube
+        - baremetal:
+            slave-label: apex-baremetal-danube
             SUT: apex
             auto-trigger-name: 'daily-trigger-disabled'
             <<: *danube
             SUT: compass
             auto-trigger-name: 'daily-trigger-disabled'
             <<: *master
-        - arm-pod2:
-            slave-label: '{pod}'
-            SUT: fuel
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *master
-        - arm-pod3:
-            slave-label: '{pod}'
-            SUT: fuel
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *master
-        - arm-virtual1:
-            slave-label: '{pod}'
-            SUT: fuel
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *master
         - zte-pod1:
             slave-label: zte-pod1
             SUT: fuel
             SUT: fuel
             auto-trigger-name: 'daily-trigger-disabled'
             <<: *danube
+        - huawei-pod4:
+            slave-label: huawei-pod4
+            SUT: apex
+            auto-trigger-name: 'apex-huawei-pod4-{testsuite}-danube-trigger'
+            <<: *danube
 #--------------------------------
     testsuite:
-        - 'debug'
         - 'compliance_set'
         - 'proposed_tests'
 
         - build-name:
             name: '$BUILD_NUMBER - Scenario: $DEPLOY_SCENARIO'
         - timeout:
-            timeout: 180
+            timeout: 300
             abort: true
         - fix-workspace-permissions
 
             artifacts: 'results/**/*'
             allow-empty: true
             fingerprint: true
+        - email-jenkins-admins-on-failure
 
 #--------------------------
 # builder macros
     builders:
         - shell:
             !include-raw: ./dovetail-cleanup.sh
+
+#--------------------------
+# trigger macros
+#--------------------------
+- trigger:
+    name: 'apex-huawei-pod4-proposed_tests-danube-trigger'
+    triggers:
+        - timed: '0 1 * * *'
+- trigger:
+    name: 'apex-huawei-pod4-compliance_set-danube-trigger'
+    triggers:
+        - timed: ''
index 3ae0cbc..2d66fe0 100755 (executable)
 # clean up dependent project docker images, which has no containers and image tag None
 clean_images=(opnfv/functest opnfv/yardstick opnfv/testapi mongo)
 for clean_image in "${clean_images[@]}"; do
-    echo "Removing image $image_id, which has no containers and image tag is None"
     dangling_images=($(docker images -f "dangling=true" | grep ${clean_image} | awk '{print $3}'))
     if [[ -n ${dangling_images} ]]; then
         for image_id in "${dangling_images[@]}"; do
+            echo "Removing image $image_id, which has no containers and image tag is None"
             docker rmi $image_id >${redirect}
         done
     fi
 done
 
-echo "Remove containers with image opnfv/dovetail:<None>..."
+echo "Remove dovetail images with tag None and containers with these images ..."
 dangling_images=($(docker images -f "dangling=true" | grep opnfv/dovetail | awk '{print $3}'))
 if [[ -n ${dangling_images} ]]; then
     for image_id in "${dangling_images[@]}"; do
@@ -37,13 +37,13 @@ if [[ ! -z $(docker ps -a | grep opnfv/dovetail) ]]; then
     docker ps -a | grep opnfv/dovetail | awk '{print $1}' | xargs docker rm -f >${redirect}
 fi
 
-echo "Remove dovetail existing images if exist..."
-if [[ ! -z $(docker images | grep opnfv/dovetail) ]]; then
-    echo "Docker images to remove:"
-    docker images | head -1 && docker images | grep opnfv/dovetail >${redirect}
-    image_tags=($(docker images | grep opnfv/dovetail | awk '{print $2}'))
-    for tag in "${image_tags[@]}"; do
-        echo "Removing docker image opnfv/dovetail:$tag..."
-        docker rmi opnfv/dovetail:$tag >${redirect}
-    done
-fi
+#echo "Remove dovetail existing images if exist..."
+#if [[ ! -z $(docker images | grep opnfv/dovetail) ]]; then
+#    echo "Docker images to remove:"
+#    docker images | head -1 && docker images | grep opnfv/dovetail >${redirect}
+#    image_tags=($(docker images | grep opnfv/dovetail | awk '{print $2}'))
+#    for tag in "${image_tags[@]}"; do
+#        echo "Removing docker image opnfv/dovetail:$tag..."
+#        docker rmi opnfv/dovetail:$tag >${redirect}
+#    done
+#fi
index 85bc54d..9c4e205 100755 (executable)
@@ -69,6 +69,8 @@ else
     exit 1
 fi
 
+set +e
+
 sudo pip install virtualenv
 
 cd ${releng_repo}/modules
@@ -81,6 +83,8 @@ if [[ ${INSTALLER_TYPE} == compass ]]; then
     options="-u root -p root"
 elif [[ ${INSTALLER_TYPE} == fuel ]]; then
     options="-u root -p r00tme"
+elif [[ ${INSTALLER_TYPE} == apex ]]; then
+    options="-u stack -k /root/.ssh/id_rsa"
 else
     echo "Don't support to generate pod.yaml on ${INSTALLER_TYPE} currently."
     echo "HA test cases may not run properly."
@@ -93,6 +97,8 @@ ${cmd}
 
 deactivate
 
+set -e
+
 cd ${WORKSPACE}
 
 if [ -f ${DOVETAIL_CONFIG}/pod.yaml ]; then
@@ -111,9 +117,31 @@ if [ "$INSTALLER_TYPE" == "fuel" ]; then
     sshpass -p r00tme sudo scp $ssh_options root@${INSTALLER_IP}:~/.ssh/id_rsa ${DOVETAIL_CONFIG}/id_rsa
 fi
 
+if [ "$INSTALLER_TYPE" == "apex" ]; then
+    echo "Fetching id_rsa file from jump_server $INSTALLER_IP..."
+    sudo scp $ssh_options stack@${INSTALLER_IP}:~/.ssh/id_rsa ${DOVETAIL_CONFIG}/id_rsa
+fi
+
+image_path=${HOME}/opnfv/dovetail/images
+if [[ ! -d ${image_path} ]]; then
+    mkdir -p ${image_path}
+fi
 # sdnvpn test case needs to download this image first before running
-echo "Download image ubuntu-16.04-server-cloudimg-amd64-disk1.img ..."
-wget -q -nc http://artifacts.opnfv.org/sdnvpn/ubuntu-16.04-server-cloudimg-amd64-disk1.img -P ${DOVETAIL_CONFIG}
+ubuntu_image=${image_path}/ubuntu-16.04-server-cloudimg-amd64-disk1.img
+if [[ ! -f ${ubuntu_image} ]]; then
+    echo "Download image ubuntu-16.04-server-cloudimg-amd64-disk1.img ..."
+    wget -q -nc http://artifacts.opnfv.org/sdnvpn/ubuntu-16.04-server-cloudimg-amd64-disk1.img -P ${image_path}
+fi
+sudo cp ${ubuntu_image} ${DOVETAIL_CONFIG}
+
+# functest needs to download this image first before running
+cirros_image=${image_path}/cirros-0.3.5-x86_64-disk.img
+if [[ ! -f ${cirros_image} ]]; then
+    echo "Download image cirros-0.3.5-x86_64-disk.img ..."
+    wget -q -nc http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img -P ${image_path}
+fi
+sudo cp ${cirros_image} ${DOVETAIL_CONFIG}
+
 
 opts="--privileged=true -id"
 
@@ -145,6 +173,37 @@ if [ $(docker ps | grep "opnfv/dovetail:${DOCKER_TAG}" | wc -l) == 0 ]; then
     exit 1
 fi
 
+# Modify tempest_conf.yaml file
+tempest_conf_file=${DOVETAIL_CONFIG}/tempest_conf.yaml
+if [[ ${INSTALLER_TYPE} == 'compass' || ${INSTALLER_TYPE} == 'apex' ]]; then
+    volume_device='vdb'
+else
+    volume_device='vdc'
+fi
+
+cat << EOF >$tempest_conf_file
+
+compute:
+    min_compute_nodes: 2
+    volume_device_name: ${volume_device}
+    min_microversion: 2.2
+    max_microversion: latest
+
+compute-feature-enabled:
+    live_migration: True
+    block_migration_for_live_migration: True
+    block_migrate_cinder_iscsi: True
+    attach_encrypted_volume: True
+
+EOF
+
+echo "${tempest_conf_file}..."
+cat ${tempest_conf_file}
+
+cp_tempest_cmd="docker cp ${DOVETAIL_CONFIG}/tempest_conf.yaml $container_id:/home/opnfv/dovetail/dovetail/userconfig"
+echo "exec command: ${cp_tempest_cmd}"
+$cp_tempest_cmd
+
 list_cmd="dovetail list ${TESTSUITE}"
 run_cmd="dovetail run --testsuite ${TESTSUITE} -d"
 echo "Container exec command: ${list_cmd}"
@@ -159,5 +218,8 @@ sudo cp -r ${DOVETAIL_HOME}/results ./
 # PRIMARY_GROUP=$(id -gn $CURRENT_USER)
 # sudo chown -R ${CURRENT_USER}:${PRIMARY_GROUP} ${WORKSPACE}/results
 
+#remove useless workspace from yardstick to save disk space
+sudo rm -rf ./results/workspace
+
 echo "Dovetail: done!"
 
index 700657d..11904cb 100644 (file)
             artifacts: 'results/**/*'
             allow-empty: true
             fingerprint: true
+        - email-jenkins-admins-on-failure
 
 ########################
 # builder macros
index 63eb044..39f3d56 100644 (file)
@@ -1,3 +1,4 @@
+---
 ###################################################
 # All the jobs except verify have been removed!
 # They will only be enabled on request by projects!
@@ -8,17 +9,17 @@
     project: '{name}'
 
     jobs:
-        - 'dpacc-verify-{stream}'
+      - 'dpacc-verify-{stream}'
 
     stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
-            disabled: false
-        - danube:
-            branch: 'stable/{stream}'
-            gs-pathname: '/{stream}'
-            disabled: false
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
+      - danube:
+          branch: 'stable/{stream}'
+          gs-pathname: '/{stream}'
+          disabled: false
 
 - job-template:
     name: 'dpacc-verify-{stream}'
     disabled: '{obj:disabled}'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'opnfv-build-ubuntu-defaults'
 
     scm:
-        - git-scm-gerrit
+      - git-scm-gerrit
 
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - patchset-created-event:
-                    exclude-drafts: 'false'
-                    exclude-trivial-rebase: 'false'
-                    exclude-no-code-change: 'false'
-                - draft-published-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'recheck'
-                - comment-added-contains-event:
-                    comment-contains-value: 'reverify'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-                disable-strict-forbidden-file-verification: 'true'
-                forbidden-file-paths:
-                  - compare-type: ANT
-                    pattern: 'docs/**|.gitignore'
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: 'recheck'
+            - comment-added-contains-event:
+                comment-contains-value: 'reverify'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              disable-strict-forbidden-file-verification: 'true'
+              forbidden-file-paths:
+                - compare-type: ANT
+                  pattern: 'docs/**|.gitignore'
 
     builders:
-        - shell: |
-            echo "Nothing to verify!"
+      - shell: |
+          echo "Nothing to verify!"
diff --git a/jjb/fuel/fuel-build.sh b/jjb/fuel/fuel-build.sh
deleted file mode 100755 (executable)
index 2c0d12a..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-
-# disable Fuel iso build for master branch
-if [[ "$BRANCH" == 'master' ]]; then
-    touch $WORKSPACE/.noupload
-    echo "--------------------------------------------------------"
-    echo "Done!"
-    exit 0
-fi
-
-set -o errexit
-set -o nounset
-set -o pipefail
-
-export TERM="vt220"
-
-cd $WORKSPACE
-
-# remove the expired items from cache
-test -f $WORKSPACE/ci/clean_cache.sh && $WORKSPACE/ci/clean_cache.sh $CACHE_DIRECTORY
-
-LATEST_ISO_PROPERTIES=$WORKSPACE/latest.iso.properties
-if [[ "$JOB_NAME" =~ "daily" ]]; then
-    # check to see if we already have an artifact on artifacts.opnfv.org
-    # for this commit during daily builds
-    echo "Checking to see if we already built and stored Fuel ISO for this commit"
-
-    curl -s -o $LATEST_ISO_PROPERTIES http://$GS_URL/latest.properties 2>/dev/null
-fi
-
-# get metadata of latest ISO
-if grep -q OPNFV_GIT_SHA1 $LATEST_ISO_PROPERTIES 2>/dev/null; then
-    LATEST_ISO_SHA1=$(grep OPNFV_GIT_SHA1 $LATEST_ISO_PROPERTIES | cut -d'=' -f2)
-    LATEST_ISO_URL=$(grep OPNFV_ARTIFACT_URL $LATEST_ISO_PROPERTIES | cut -d'=' -f2)
-else
-    LATEST_ISO_SHA1=none
-fi
-
-# get current SHA1
-CURRENT_SHA1=$(git rev-parse HEAD)
-
-# set FORCE_BUILD to false for non-daily builds
-FORCE_BUILD=${FORCE_BUILD:-false}
-
-if [[ "$CURRENT_SHA1" == "$LATEST_ISO_SHA1" && "$FORCE_BUILD" == "false" ]]; then
-    echo "***************************************************"
-    echo "   An ISO has already been built for this commit"
-    echo "   $LATEST_ISO_URL"
-    echo "***************************************************"
-#    echo "Nothing new to build. Exiting."
-#    touch $WORKSPACE/.noupload
-#    exit 0
-else
-    echo "This commit has not been built yet or forced build! Proceeding with the build."
-    /bin/rm -f $LATEST_ISO_PROPERTIES
-    echo
-fi
-
-# log info to console
-echo "Starting the build of $INSTALLER_TYPE. This could take some time..."
-echo "--------------------------------------------------------"
-echo
-
-# create the cache directory if it doesn't exist
-mkdir -p $CACHE_DIRECTORY
-
-# set OPNFV_ARTIFACT_VERSION
-if [[ "$JOB_NAME" =~ "merge" ]]; then
-    echo "Building Fuel ISO for a merged change"
-    export OPNFV_ARTIFACT_VERSION="gerrit-$GERRIT_CHANGE_NUMBER"
-else
-    export OPNFV_ARTIFACT_VERSION=$(date -u +"%Y-%m-%d_%H-%M-%S")
-fi
-
-NOCACHE_PATTERN="verify: no-cache"
-if [[ "$JOB_NAME" =~ "verify" && "$GERRIT_CHANGE_COMMIT_MESSAGE" =~ "$NOCACHE_PATTERN" ]]; then
-    echo "The cache will not be used for this build!"
-    NOCACHE_ARG="-f P"
-fi
-NOCACHE_ARG=${NOCACHE_ARG:-}
-
-# start the build
-cd $WORKSPACE/ci
-./build.sh -v $OPNFV_ARTIFACT_VERSION $NOCACHE_ARG -c file://$CACHE_DIRECTORY $BUILD_DIRECTORY
-
-# list the build artifacts
-ls -al $BUILD_DIRECTORY
-
-# save information regarding artifact into file
-(
-    echo "OPNFV_ARTIFACT_VERSION=$OPNFV_ARTIFACT_VERSION"
-    echo "OPNFV_GIT_URL=$(git config --get remote.origin.url)"
-    echo "OPNFV_GIT_SHA1=$(git rev-parse HEAD)"
-    echo "OPNFV_ARTIFACT_URL=$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso"
-    echo "OPNFV_ARTIFACT_SHA512SUM=$(sha512sum $BUILD_DIRECTORY/opnfv-$OPNFV_ARTIFACT_VERSION.iso | cut -d' ' -f1)"
-    echo "OPNFV_BUILD_URL=$BUILD_URL"
-) > $WORKSPACE/opnfv.properties
-
-echo
-echo "--------------------------------------------------------"
-echo "Done!"
index 6867708..c30cfed 100644 (file)
         branch: '{stream}'
         disabled: false
         gs-pathname: ''
+    euphrates: &euphrates
+        stream: euphrates
+        branch: 'stable/{stream}'
+        disabled: true
+        gs-pathname: '/{stream}'
     danube: &danube
         stream: danube
         branch: 'stable/{stream}'
             <<: *master
         - baremetal:
             slave-label: fuel-baremetal
-            <<: *danube
+            <<: *euphrates
         - virtual:
             slave-label: fuel-virtual
-            <<: *danube
+            <<: *euphrates
 #--------------------------------
 #        None-CI PODs
 #--------------------------------
         - zte-pod1:
             slave-label: zte-pod1
             <<: *master
-        - zte-pod2:
-            slave-label: zte-pod2
-            <<: *master
         - zte-pod3:
             slave-label: zte-pod3
             <<: *master
         - zte-pod1:
             slave-label: zte-pod1
-            <<: *danube
+            <<: *euphrates
         - zte-pod3:
             slave-label: zte-pod3
+            <<: *euphrates
+        - zte-pod1:
+            slave-label: zte-pod1
             <<: *danube
 #--------------------------------
 #       scenarios
         # HA scenarios
         - 'os-nosdn-nofeature-ha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
-        - 'os-odl_l2-nofeature-ha':
-            auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
-        - 'os-odl_l3-nofeature-ha':
+        - 'os-odl-nofeature-ha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
         - 'os-onos-sfc-ha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
         - 'os-onos-nofeature-ha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
-        - 'os-odl_l2-sfc-ha':
-            auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
-        - 'os-odl_l2-bgpvpn-ha':
-            auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
         - 'os-nosdn-kvm-ha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
         - 'os-nosdn-ovs-ha':
         # NOHA scenarios
         - 'os-nosdn-nofeature-noha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
-        - 'os-odl_l2-nofeature-noha':
-            auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
-        - 'os-odl_l3-nofeature-noha':
+        - 'os-odl-nofeature-noha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
         - 'os-onos-sfc-noha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
         - 'os-onos-nofeature-noha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
-        - 'os-odl_l2-sfc-noha':
-            auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
-        - 'os-odl_l2-bgpvpn-noha':
-            auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
         - 'os-nosdn-kvm-noha':
             auto-trigger-name: 'fuel-{scenario}-{pod}-daily-{stream}-trigger'
         - 'os-nosdn-ovs-noha':
             blocking-jobs:
                 - 'fuel-os-.*?-{pod}-daily-.*'
                 - 'fuel-os-.*?-{pod}-weekly-.*'
+                - 'fuel-verify-.*'
             block-level: 'NODE'
 
     wrappers:
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - '{installer}-defaults'
+        - '{installer}-defaults':
+            gs-pathname: '{gs-pathname}'
         - '{slave-label}-defaults':
             installer: '{installer}'
         - string:
             name: DEPLOY_SCENARIO
             default: '{scenario}'
-        - fuel-ci-parameter:
-            gs-pathname: '{gs-pathname}'
 
     builders:
         - description-setter:
         # 2.here the stream means the SUT stream, dovetail stream is defined in its own job
         # 3.only debug testsuite here(refstack, ha, ipv6, bgpvpn)
         # 4.not used for release criteria or compliance,
-        #   only to debug the dovetail tool bugs with bgpvpn
-        # 5,only run against scenario os-odl_l2-bgpvpn-ha(regex used here, can extend to more scenarios future)
+        #   only to debug the dovetail tool bugs with bgpvpn and nosdn-nofeature
+        # 5.only run against scenario os-odl-bgpvpn-ha(regex used here, can extend to more scenarios future)
+        # 6.ZTE pod1, os-nosdn-nofeature-ha and os-odl-bgpvpn-ha, run against danube
         - conditional-step:
             condition-kind: regex-match
-            regex: os-odl_l2-bgpvpn-ha
+            regex: os-(nosdn-nofeature|odl-bgpvpn)-ha
             label: '{scenario}'
             steps:
                 - trigger-builds:
     publishers:
         - email:
             recipients: peter.barabas@ericsson.com fzhadaev@mirantis.com
+        - email-jenkins-admins-on-failure
 
 - job-template:
     name: 'fuel-deploy-{pod}-daily-{stream}'
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - '{installer}-defaults'
+        - '{installer}-defaults':
+            gs-pathname: '{gs-pathname}'
         - '{slave-label}-defaults':
             installer: '{installer}'
         - string:
             name: DEPLOY_SCENARIO
-            default: 'os-odl_l2-nofeature-ha'
-        - fuel-ci-parameter:
-            gs-pathname: '{gs-pathname}'
+            default: 'os-odl-nofeature-ha'
         - string:
             name: DEPLOY_TIMEOUT
             default: '150'
     publishers:
         - email:
             recipients: peter.barabas@ericsson.com fzhadaev@mirantis.com
+        - email-jenkins-admins-on-failure
 
 ########################
-# parameter macros
-########################
-- parameter:
-    name: fuel-ci-parameter
-    parameters:
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
-        - string:
-            name: CACHE_DIRECTORY
-            default: $HOME/opnfv/cache/$INSTALLER_TYPE
-            description: "Directory where the cache to be used during the build is located."
-        - string:
-            name: GS_URL
-            default: artifacts.opnfv.org/$PROJECT{gs-pathname}
-            description: "URL to Google Storage."
-        - string:
-            name: SSH_KEY
-            default: "/tmp/mcp.rsa"
-            description: "Path to private SSH key to access environment nodes. For MCP deployments only."
-########################
 # trigger macros
 ########################
 #-----------------------------------------------
 - trigger:
     name: 'fuel-os-nosdn-nofeature-ha-baremetal-daily-master-trigger'
     triggers:
-        - timed: '' # '5 20 * * *'
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-baremetal-daily-master-trigger'
-    triggers:
-        - timed: '' # '5 23 * * *'
+        - timed: '5 20 * * *'
 - trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-baremetal-daily-master-trigger'
+    name: 'fuel-os-odl-nofeature-ha-baremetal-daily-master-trigger'
     triggers:
-        - timed: '' # '5 2 * * *'
+        - timed: '5 2 * * *'
 - trigger:
     name: 'fuel-os-nosdn-ovs-ha-baremetal-daily-master-trigger'
     triggers:
-        - timed: '' # '5 5 * * *'
+        - timed: '5 5 * * *'
 - trigger:
     name: 'fuel-os-onos-sfc-ha-baremetal-daily-master-trigger'
     triggers:
     name: 'fuel-os-onos-nofeature-ha-baremetal-daily-master-trigger'
     triggers:
         - timed: '' # '5 8 * * *'
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-baremetal-daily-master-trigger'
-    triggers:
-        - timed: '' # '5 11 * * *'
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-baremetal-daily-master-trigger'
-    triggers:
-        - timed: '' # '5 14 * * *'
 - trigger:
     name: 'fuel-os-nosdn-kvm-ha-baremetal-daily-master-trigger'
     triggers:
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-baremetal-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-baremetal-daily-master-trigger'
+    name: 'fuel-os-odl-nofeature-noha-baremetal-daily-master-trigger'
     triggers:
         - timed: ''
 - trigger:
     name: 'fuel-os-onos-nofeature-noha-baremetal-daily-master-trigger'
     triggers:
         - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-baremetal-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-baremetal-daily-master-trigger'
-    triggers:
-        - timed: ''
 - trigger:
     name: 'fuel-os-nosdn-kvm-noha-baremetal-daily-master-trigger'
     triggers:
     triggers:
         - timed: ''
 #-----------------------------------------------
-# Triggers for job running on fuel-baremetal against danube branch
+# Triggers for job running on fuel-baremetal against euphrates branch
 #-----------------------------------------------
 # HA Scenarios
 - trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-ha-baremetal-daily-euphrates-trigger'
     triggers:
-        - timed: '0 20 * * *'
+        - timed: '' # '0 20 * * *'
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-ha-baremetal-daily-euphrates-trigger'
     triggers:
-        - timed: '0 23 * * *'
+        - timed: '' # '0 2 * * *'
 - trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-baremetal-daily-danube-trigger'
-    triggers:
-        - timed: '0 2 * * *'
-- trigger:
-    name: 'fuel-os-onos-sfc-ha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-ha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: '' # '0 5 * * *'
 - trigger:
-    name: 'fuel-os-onos-nofeature-ha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-ha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: '' # '0 8 * * *'
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-baremetal-daily-danube-trigger'
-    triggers:
-        - timed: '0 11 * * *'
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-ha-baremetal-daily-euphrates-trigger'
     triggers:
-        - timed: '0 14 * * *'
+        - timed: '' # '0 17 * * *'
 - trigger:
-    name: 'fuel-os-nosdn-kvm-ha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-ha-baremetal-daily-euphrates-trigger'
     triggers:
-        - timed: '0 17 * * *'
+        - timed: '' # '0 20 * * *'
 - trigger:
-    name: 'fuel-os-nosdn-ovs-ha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-baremetal-daily-euphrates-trigger'
     triggers:
-        - timed: '0 20 * * *'
+        - timed: '' # '0 12 * * *'
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-baremetal-daily-euphrates-trigger'
     triggers:
-        - timed: '0 12 * * *'
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-baremetal-daily-danube-trigger'
-    triggers:
-        - timed: '0 8 * * *'
+        - timed: '' # '0 8 * * *'
 # NOHA Scenarios
 - trigger:
-    name: 'fuel-os-nosdn-nofeature-noha-baremetal-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-baremetal-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-noha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-sfc-noha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-noha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-nofeature-noha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-noha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-noha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-noha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm-noha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-noha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-ovs-noha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-baremetal-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-baremetal-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-baremetal-daily-euphrates-trigger'
     triggers:
         - timed: ''
 #-----------------------------------------------
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-virtual-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-virtual-daily-master-trigger'
+    name: 'fuel-os-odl-nofeature-ha-virtual-daily-master-trigger'
     triggers:
         - timed: ''
 - trigger:
     name: 'fuel-os-onos-nofeature-ha-virtual-daily-master-trigger'
     triggers:
         - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-virtual-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-virtual-daily-master-trigger'
-    triggers:
-        - timed: ''
 - trigger:
     name: 'fuel-os-nosdn-kvm-ha-virtual-daily-master-trigger'
     triggers:
     triggers:
         - timed: '5 13 * * *'
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-virtual-daily-master-trigger'
-    triggers:
-        - timed: '' # '35 15 * * *'
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-virtual-daily-master-trigger'
+    name: 'fuel-os-odl-nofeature-noha-virtual-daily-master-trigger'
     triggers:
-        - timed: '' # '5 18 * * *'
+        - timed: '5 18 * * *'
 - trigger:
     name: 'fuel-os-onos-sfc-noha-virtual-daily-master-trigger'
     triggers:
     name: 'fuel-os-onos-nofeature-noha-virtual-daily-master-trigger'
     triggers:
         - timed: '' # '5 23 * * *'
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-virtual-daily-master-trigger'
-    triggers:
-        - timed: '' # '35 1 * * *'
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-virtual-daily-master-trigger'
-    triggers:
-        - timed: '' # '5 4 * * *'
 - trigger:
     name: 'fuel-os-nosdn-kvm-noha-virtual-daily-master-trigger'
     triggers:
 - trigger:
     name: 'fuel-os-nosdn-ovs-noha-virtual-daily-master-trigger'
     triggers:
-        - timed: '' # '5 9 * * *'
+        - timed: '5 9 * * *'
 - trigger:
     name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-virtual-daily-master-trigger'
     triggers:
     triggers:
         - timed: '' # '30 20 * * *'
 #-----------------------------------------------
-# Triggers for job running on fuel-virtual against danube branch
+# Triggers for job running on fuel-virtual against euphrates branch
 #-----------------------------------------------
 - trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-ha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-virtual-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-ha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-virtual-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-ha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-sfc-ha-virtual-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-ha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-nofeature-ha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-ha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-ha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm-ha-virtual-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-ovs-ha-virtual-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-virtual-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: ''
 # NOHA Scenarios
 - trigger:
-    name: 'fuel-os-nosdn-nofeature-noha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-noha-virtual-daily-euphrates-trigger'
     triggers:
-        - timed: '0 13 * * *'
+        - timed: '' # '0 13 * * *'
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-virtual-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-noha-virtual-daily-euphrates-trigger'
     triggers:
-        - timed: '30 15 * * *'
+        - timed: '' # '0 18 * * *'
 - trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-virtual-daily-danube-trigger'
-    triggers:
-        - timed: '0 18 * * *'
-- trigger:
-    name: 'fuel-os-onos-sfc-noha-virtual-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-noha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: '' # '30 20 * * *'
 - trigger:
-    name: 'fuel-os-onos-nofeature-noha-virtual-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-noha-virtual-daily-euphrates-trigger'
     triggers:
         - timed: '' # '0 23 * * *'
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-virtual-daily-danube-trigger'
-    triggers:
-        - timed: '30 1 * * *'
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-noha-virtual-daily-euphrates-trigger'
     triggers:
-        - timed: '0 4 * * *'
+        - timed: '' # '30 6 * * *'
 - trigger:
-    name: 'fuel-os-nosdn-kvm-noha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-noha-virtual-daily-euphrates-trigger'
     triggers:
-        - timed: '30 6 * * *'
+        - timed: '' # '0 9 * * *'
 - trigger:
-    name: 'fuel-os-nosdn-ovs-noha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-virtual-daily-euphrates-trigger'
     triggers:
-        - timed: '0 9 * * *'
+        - timed: '' # '0 16 * * *'
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-virtual-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-virtual-daily-euphrates-trigger'
     triggers:
-        - timed: '0 16 * * *'
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-virtual-daily-danube-trigger'
-    triggers:
-        - timed: '0 20 * * *'
+        - timed: '' # '0 20 * * *'
 #-----------------------------------------------
 # ZTE POD1 Triggers running against master branch
 #-----------------------------------------------
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-zte-pod1-daily-master-trigger'
-    triggers:
-        - timed: '0 10 * * *'
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-zte-pod1-daily-master-trigger'
+    name: 'fuel-os-odl-nofeature-ha-zte-pod1-daily-master-trigger'
     triggers:
         - timed: ''
 - trigger:
     name: 'fuel-os-onos-nofeature-ha-zte-pod1-daily-master-trigger'
     triggers:
         - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-zte-pod1-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-zte-pod1-daily-master-trigger'
-    triggers:
-        - timed: ''
 - trigger:
     name: 'fuel-os-nosdn-kvm-ha-zte-pod1-daily-master-trigger'
     triggers:
 - trigger:
     name: 'fuel-os-nosdn-ovs-ha-zte-pod1-daily-master-trigger'
     triggers:
-        - timed: ''
+        - timed: '0 18 * * *'
 - trigger:
     name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-zte-pod1-daily-master-trigger'
     triggers:
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-zte-pod1-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-zte-pod1-daily-master-trigger'
+    name: 'fuel-os-odl-nofeature-noha-zte-pod1-daily-master-trigger'
     triggers:
         - timed: ''
 - trigger:
     name: 'fuel-os-onos-nofeature-noha-zte-pod1-daily-master-trigger'
     triggers:
         - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-zte-pod1-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-zte-pod1-daily-master-trigger'
-    triggers:
-        - timed: ''
 - trigger:
     name: 'fuel-os-nosdn-kvm-noha-zte-pod1-daily-master-trigger'
     triggers:
     name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-zte-pod1-daily-master-trigger'
     triggers:
         - timed: ''
-
-#-----------------------------------------------
-# ZTE POD2 Triggers running against master branch
-#-----------------------------------------------
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-onos-sfc-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-onos-nofeature-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-ovs-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-# NOHA Scenarios
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-onos-sfc-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-onos-nofeature-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-ovs-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-zte-pod2-daily-master-trigger'
-    triggers:
-        - timed: ''
 #-----------------------------------------------
 # ZTE POD3 Triggers running against master branch
 #-----------------------------------------------
 - trigger:
     name: 'fuel-os-nosdn-nofeature-ha-zte-pod3-daily-master-trigger'
     triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-zte-pod3-daily-master-trigger'
-    triggers:
-        - timed: ''
+        - timed: '0 10 * * *'
 - trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-zte-pod3-daily-master-trigger'
+    name: 'fuel-os-odl-nofeature-ha-zte-pod3-daily-master-trigger'
     triggers:
         - timed: ''
 - trigger:
     name: 'fuel-os-onos-nofeature-ha-zte-pod3-daily-master-trigger'
     triggers:
         - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-zte-pod3-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-zte-pod3-daily-master-trigger'
-    triggers:
-        - timed: ''
 - trigger:
     name: 'fuel-os-nosdn-kvm-ha-zte-pod3-daily-master-trigger'
     triggers:
-        - timed: '0 10 * * *'
+        - timed: ''
 - trigger:
     name: 'fuel-os-nosdn-ovs-ha-zte-pod3-daily-master-trigger'
     triggers:
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-zte-pod3-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-zte-pod3-daily-master-trigger'
+    name: 'fuel-os-odl-nofeature-noha-zte-pod3-daily-master-trigger'
     triggers:
         - timed: ''
 - trigger:
     name: 'fuel-os-onos-nofeature-noha-zte-pod3-daily-master-trigger'
     triggers:
         - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-zte-pod3-daily-master-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-zte-pod3-daily-master-trigger'
-    triggers:
-        - timed: ''
 - trigger:
     name: 'fuel-os-nosdn-kvm-noha-zte-pod3-daily-master-trigger'
     triggers:
     triggers:
         - timed: ''
 #-----------------------------------------------
-# ZTE POD1 Triggers running against danube branch
+# ZTE POD1 Triggers running against euphrates branch
 #-----------------------------------------------
 - trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-zte-pod1-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-zte-pod1-daily-danube-trigger'
-    triggers:
-        - timed: '0 2 * * *'
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-ha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-sfc-ha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-ha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-nofeature-ha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-ha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-ha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-ha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm-ha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-ha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-ovs-ha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-zte-pod1-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 # NOHA Scenarios
 - trigger:
-    name: 'fuel-os-nosdn-nofeature-noha-zte-pod1-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-zte-pod1-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-zte-pod1-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-onos-sfc-noha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-noha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-nofeature-noha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-noha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-noha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-noha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm-noha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-noha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-ovs-noha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-noha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-zte-pod1-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-zte-pod1-daily-euphrates-trigger'
     triggers:
         - timed: ''
-
 #-----------------------------------------------
-# ZTE POD2 Triggers running against danube branch
+# ZTE POD3 Triggers running against euphrates branch
 #-----------------------------------------------
 - trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-zte-pod2-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-zte-pod2-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-ha-zte-pod3-daily-euphrates-trigger'
     triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-onos-sfc-ha-zte-pod2-daily-danube-trigger'
-    triggers:
-        - timed: ''
+        - timed: '' # '0 18 * * *'
 - trigger:
-    name: 'fuel-os-onos-nofeature-ha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-ha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-ha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-ha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm-ha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-ha-zte-pod3-daily-euphrates-trigger'
     triggers:
-        - timed: ''
+        - timed: '' # '0 2 * * *'
 - trigger:
-    name: 'fuel-os-nosdn-ovs-ha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-ha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 # NOHA Scenarios
 - trigger:
-    name: 'fuel-os-nosdn-nofeature-noha-zte-pod2-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-zte-pod2-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-zte-pod2-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-onos-sfc-noha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-noha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-nofeature-noha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-noha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-noha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-noha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm-noha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-noha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-ovs-noha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-noha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-zte-pod2-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-zte-pod2-daily-danube-trigger'
-    triggers:
-        - timed: ''
-#-----------------------------------------------
-# ZTE POD3 Triggers running against danube branch
-#-----------------------------------------------
-- trigger:
-    name: 'fuel-os-nosdn-nofeature-ha-zte-pod3-daily-danube-trigger'
-    triggers:
-        - timed: '0 18 * * *'
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-ha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-zte-pod3-daily-euphrates-trigger'
     triggers:
         - timed: ''
+#------------------------------------------------
+# ZTE POD1 Triggers running against danube branch
+#------------------------------------------------
 - trigger:
-    name: 'fuel-os-odl_l3-nofeature-ha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-ha-zte-pod1-daily-danube-trigger'
     triggers:
-        - timed: ''
+        - timed: '0 2 * * 6'
 - trigger:
-    name: 'fuel-os-onos-sfc-ha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-ha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-nofeature-ha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-ha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-ha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-ha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-ha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-ha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm-ha-zte-pod3-daily-danube-trigger'
-    triggers:
-        - timed: '0 2 * * *'
-- trigger:
-    name: 'fuel-os-nosdn-ovs-ha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-ha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-ha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-ha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 # NOHA Scenarios
 - trigger:
-    name: 'fuel-os-nosdn-nofeature-noha-zte-pod3-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l2-nofeature-noha-zte-pod3-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-odl_l3-nofeature-noha-zte-pod3-daily-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'fuel-os-onos-sfc-noha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-nofeature-noha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-onos-nofeature-noha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-odl-nofeature-noha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-sfc-noha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-onos-sfc-noha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-odl_l2-bgpvpn-noha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-onos-nofeature-noha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm-noha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm-noha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-ovs-noha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-ovs-noha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk-noha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
 - trigger:
-    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-zte-pod3-daily-danube-trigger'
+    name: 'fuel-os-nosdn-kvm_ovs_dpdk_bar-noha-zte-pod1-daily-danube-trigger'
     triggers:
         - timed: ''
index 2fb5c71..6525c7c 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 # SPDX-license-identifier: Apache-2.0
 ##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
+# Copyright (c) 2017 Ericsson AB, Mirantis Inc., Enea Software AB and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Apache License, Version 2.0
 # which accompanies this distribution, and is available at
@@ -12,7 +12,7 @@ set -o pipefail
 
 export TERM="vt220"
 
-if [[ "$BRANCH" != 'master' ]]; then
+if [[ "$BRANCH" =~ 'danube' ]]; then
     # source the file so we get OPNFV vars
     source latest.properties
 
@@ -20,75 +20,99 @@ if [[ "$BRANCH" != 'master' ]]; then
     echo "Using ${OPNFV_ARTIFACT_URL/*\/} for deployment"
 fi
 
-if [[ "$JOB_NAME" =~ "merge" ]]; then
-    # set simplest scenario for virtual deploys to run for merges
+# shellcheck disable=SC2153
+if [[ "${JOB_NAME}" =~ 'verify' ]]; then
+    # set simplest scenario for virtual deploys to run for verify
     DEPLOY_SCENARIO="os-nosdn-nofeature-ha"
-elif [[ "$BRANCH" != 'master' ]]; then
-    # for none-merge deployments
+elif [[ "${BRANCH}" =~ 'danube' ]]; then
+    # for Danube deployments (no artifact for current master or newer branches)
     # checkout the commit that was used for building the downloaded artifact
     # to make sure the ISO and deployment mechanism uses same versions
-    echo "Checking out $OPNFV_GIT_SHA1"
-    git checkout $OPNFV_GIT_SHA1 --quiet
+    echo "Checking out ${OPNFV_GIT_SHA1}"
+    git checkout "${OPNFV_GIT_SHA1}" --quiet
 fi
 
 # set deployment parameters
-export TMPDIR=$HOME/tmpdir
+export TMPDIR=${HOME}/tmpdir
 BRIDGE=${BRIDGE:-pxebr}
+# shellcheck disable=SC2153
 LAB_NAME=${NODE_NAME/-*}
+# shellcheck disable=SC2153
 POD_NAME=${NODE_NAME/*-}
-
-if [[ "$NODE_NAME" =~ "virtual" ]]; then
-    POD_NAME="virtual_kvm"
-fi
-
-# we currently support ericsson, intel, lf and zte labs
-if [[ ! "$LAB_NAME" =~ (ericsson|intel|lf|zte) ]]; then
-    echo "Unsupported/unidentified lab $LAB_NAME. Cannot continue!"
-    exit 1
+# Armband might override LAB_CONFIG_URL, all others use the default
+LAB_CONFIG_URL=${LAB_CONFIG_URL:-'ssh://jenkins-ericsson@gerrit.opnfv.org:29418/securedlab'}
+
+# Fuel requires deploy script to be ran with sudo, Armband does not
+SUDO='sudo -E'
+if [ "${PROJECT}" = 'fuel' ]; then
+    # Fuel does not use any POD-specific configuration for virtual deploys
+    if [[ "${NODE_NAME}" =~ "virtual" ]]; then
+        POD_NAME="virtual_kvm"
+    fi
+    # Fuel currently supports ericsson, intel, lf and zte labs
+    if [[ ! "${LAB_NAME}" =~ (ericsson|intel|lf|zte) ]]; then
+        echo "Unsupported/unidentified lab ${LAB_NAME}. Cannot continue!"
+        exit 1
+    fi
 else
-    echo "Using configuration for $LAB_NAME"
+    SUDO=
+    # Armband currently supports arm, enea labs
+    if [[ ! "${LAB_NAME}" =~ (arm|enea) ]]; then
+        echo "Unsupported/unidentified lab ${LAB_NAME}. Cannot continue!"
+        exit 1
+    fi
 fi
 
-# create TMPDIR if it doesn't exist
-export TMPDIR=$HOME/tmpdir
-mkdir -p $TMPDIR
+echo "Using configuration for ${LAB_NAME}"
+
+# create TMPDIR if it doesn't exist, change permissions
+mkdir -p "${TMPDIR}"
+chmod a+x "${HOME}" "${TMPDIR}"
 
-# change permissions down to TMPDIR
-chmod a+x $HOME
-chmod a+x $TMPDIR
+cd "${WORKSPACE}" || exit 1
+if [[ "${LAB_CONFIG_URL}" =~ ^(git|ssh):// ]]; then
+    echo "Cloning securedlab repo ${BRANCH}"
+    git clone --quiet --branch "${BRANCH}" "${LAB_CONFIG_URL}" lab-config
+    LAB_CONFIG_URL=file://${WORKSPACE}/lab-config
 
-# clone the securedlab repo
-cd $WORKSPACE
-echo "Cloning securedlab repo $BRANCH"
-git clone ssh://jenkins-ericsson@gerrit.opnfv.org:29418/securedlab --quiet \
-    --branch $BRANCH
+    # Source local_env if present, which contains POD-specific config
+    local_env="${WORKSPACE}/lab-config/labs/${LAB_NAME}/${POD_NAME}/fuel/config/local_env"
+    if [ -e "${local_env}" ]; then
+        echo "-- Sourcing local environment file"
+        source "${local_env}"
+    fi
+fi
+
+# releng wants us to use nothing else but opnfv.iso for now. We comply.
+ISO_FILE=file://${WORKSPACE}/opnfv.iso
 
 # log file name
 FUEL_LOG_FILENAME="${JOB_NAME}_${BUILD_NUMBER}.log.tar.gz"
 
 # construct the command
-DEPLOY_COMMAND="sudo $WORKSPACE/ci/deploy.sh -b file://$WORKSPACE/securedlab \
-    -l $LAB_NAME -p $POD_NAME -s $DEPLOY_SCENARIO -i file://$WORKSPACE/opnfv.iso \
-    -H -B $BRIDGE -S $TMPDIR -L $WORKSPACE/$FUEL_LOG_FILENAME"
+DEPLOY_COMMAND="${SUDO} ${WORKSPACE}/ci/deploy.sh -b ${LAB_CONFIG_URL} \
+    -l ${LAB_NAME} -p ${POD_NAME} -s ${DEPLOY_SCENARIO} -i ${ISO_FILE} \
+    -B ${DEFAULT_BRIDGE:-${BRIDGE}} -S ${TMPDIR} \
+    -L ${WORKSPACE}/${FUEL_LOG_FILENAME}"
 
 # log info to console
 echo "Deployment parameters"
 echo "--------------------------------------------------------"
-echo "Scenario: $DEPLOY_SCENARIO"
-echo "Lab: $LAB_NAME"
-echo "POD: $POD_NAME"
-[[ "$BRANCH" != 'master' ]] && echo "ISO: ${OPNFV_ARTIFACT_URL/*\/}"
+echo "Scenario: ${DEPLOY_SCENARIO}"
+echo "Lab: ${LAB_NAME}"
+echo "POD: ${POD_NAME}"
+[[ "${BRANCH}" != 'master' ]] && echo "ISO: ${OPNFV_ARTIFACT_URL/*\/}"
 echo
-echo "Starting the deployment using $INSTALLER_TYPE. This could take some time..."
+echo "Starting the deployment using ${INSTALLER_TYPE}. This could take some time..."
 echo "--------------------------------------------------------"
 echo
 
 # start the deployment
 echo "Issuing command"
-echo "$DEPLOY_COMMAND"
+echo "${DEPLOY_COMMAND}"
 echo
 
-$DEPLOY_COMMAND
+${DEPLOY_COMMAND}
 exit_code=$?
 
 echo
@@ -96,17 +120,18 @@ echo "--------------------------------------------------------"
 echo "Deployment is done!"
 
 # upload logs for baremetal deployments
-# work with virtual deployments is still going on so we skip that for the timebeing
-if [[ "$JOB_NAME" =~ (baremetal-daily|baremetal-weekly) ]]; then
+# work with virtual deployments is still going on, so skip that for now
+if [[ "${JOB_NAME}" =~ (baremetal-daily|baremetal-weekly) ]]; then
     echo "Uploading deployment logs"
-    gsutil cp $WORKSPACE/$FUEL_LOG_FILENAME gs://$GS_URL/logs/$FUEL_LOG_FILENAME > /dev/null 2>&1
-    echo "Logs are available as http://$GS_URL/logs/$FUEL_LOG_FILENAME"
+    gsutil cp "${WORKSPACE}/${FUEL_LOG_FILENAME}" \
+        "gs://${GS_URL}/logs/${FUEL_LOG_FILENAME}" > /dev/null 2>&1
+    echo "Logs are available at http://${GS_URL}/logs/${FUEL_LOG_FILENAME}"
 fi
 
-if [[ $exit_code -ne 0 ]]; then
+if [[ "${exit_code}" -ne 0 ]]; then
     echo "Deployment failed!"
-    exit $exit_code
-else
-    echo "Deployment is successful!"
-    exit 0
+    exit "${exit_code}"
 fi
+
+echo "Deployment is successful!"
+exit 0
index c3b8253..02ca103 100755 (executable)
@@ -11,20 +11,14 @@ set -o errexit
 set -o pipefail
 
 # disable Fuel ISO download for master branch
-[[ "$BRANCH" == 'master' ]] && exit 0
+[[ ! "$BRANCH" =~ (danube) ]] && exit 0
 
-# use proxy url to replace the nomral URL, for googleusercontent.com will be blocked randomly
+# use proxy url to replace the normal URL, or googleusercontent.com will be blocked randomly
 [[ "$NODE_NAME" =~ (zte) ]] && GS_URL=${GS_BASE_PROXY%%/*}/$GS_URL
 
-if [[ "$JOB_NAME" =~ "merge" ]]; then
-    echo "Downloading http://$GS_URL/opnfv-gerrit-$GERRIT_CHANGE_NUMBER.properties"
-    # get the properties file for the Fuel ISO built for a merged change
-    curl -L -s -o $WORKSPACE/latest.properties http://$GS_URL/opnfv-gerrit-$GERRIT_CHANGE_NUMBER.properties
-else
-    # get the latest.properties file in order to get info regarding latest artifact
-    echo "Downloading http://$GS_URL/latest.properties"
-    curl -L -s -o $WORKSPACE/latest.properties http://$GS_URL/latest.properties
-fi
+# get the latest.properties file in order to get info regarding latest artifact
+echo "Downloading http://$GS_URL/latest.properties"
+curl -L -s -o $WORKSPACE/latest.properties http://$GS_URL/latest.properties
 
 # check if we got the file
 [[ -f $WORKSPACE/latest.properties ]] || exit 1
@@ -36,21 +30,18 @@ source $WORKSPACE/latest.properties
 OPNFV_ARTIFACT=${OPNFV_ARTIFACT_URL/*\/}
 echo "Using $OPNFV_ARTIFACT for deployment"
 
-# using ISOs for verify & merge jobs from local storage will be enabled later
-if [[ ! "$JOB_NAME" =~ (verify|merge) ]]; then
-    # check if we already have the ISO to avoid redownload
-    ISOSTORE="/iso_mount/opnfv_ci/${BRANCH##*/}"
-    if [[ -f "$ISOSTORE/$OPNFV_ARTIFACT" ]]; then
-        echo "ISO exists locally. Skipping the download and using the file from ISO store"
-        ln -s $ISOSTORE/$OPNFV_ARTIFACT $WORKSPACE/opnfv.iso
-        echo "--------------------------------------------------------"
-        echo
-        ls -al $WORKSPACE/opnfv.iso
-        echo
-        echo "--------------------------------------------------------"
-        echo "Done!"
-        exit 0
-    fi
+# check if we already have the ISO to avoid redownload
+ISOSTORE="/iso_mount/opnfv_ci/${BRANCH##*/}"
+if [[ -f "$ISOSTORE/$OPNFV_ARTIFACT" ]]; then
+    echo "ISO exists locally. Skipping the download and using the file from ISO store"
+    ln -s $ISOSTORE/$OPNFV_ARTIFACT $WORKSPACE/opnfv.iso
+    echo "--------------------------------------------------------"
+    echo
+    ls -al $WORKSPACE/opnfv.iso
+    echo
+    echo "--------------------------------------------------------"
+    echo "Done!"
+    exit 0
 fi
 
 [[ "$NODE_NAME" =~ (zte) ]] && OPNFV_ARTIFACT_URL=${GS_BASE_PROXY%%/*}/$OPNFV_ARTIFACT_URL
index 1f0ddd3..cfcbf36 100644 (file)
             branch: '{stream}'
             gs-pathname: ''
             disabled: false
-        - danube:
+        - euphrates:
             branch: 'stable/{stream}'
             gs-pathname: '/{stream}'
-            disabled: false
+            disabled: true
 
     jobs:
-        - 'fuel-build-daily-{stream}'
-        - 'fuel-merge-build-{stream}'
-        - 'fuel-merge-deploy-virtual-{stream}'
         - 'fuel-deploy-generic-daily-{stream}'
 
 ########################
 # job templates
 ########################
-- job-template:
-    name: 'fuel-build-daily-{stream}'
-
-    disabled: '{obj:disabled}'
-
-    concurrent: false
-
-    properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 1
-            max-per-node: 1
-            option: 'project'
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
-        - '{installer}-defaults'
-        - choice:
-            name: FORCE_BUILD
-            choices:
-              - 'false'
-              - 'true'
-            description: "Force build even if there is no changes in fuel repo. Default false"
-        - fuel-project-parameter:
-            gs-pathname: '{gs-pathname}'
-
-    scm:
-        - git-scm
-
-    triggers:
-        - timed: '0 H/4 * * *'
-
-    wrappers:
-        - timeout:
-            timeout: 360
-            fail: true
-
-    builders:
-        - shell:
-            !include-raw-escape: ./fuel-build.sh
-        - shell:
-            !include-raw-escape: ./fuel-upload-artifact.sh
-        - shell:
-            !include-raw-escape: ./fuel-workspace-cleanup.sh
-
-    publishers:
-        - email:
-            recipients: fzhadaev@mirantis.com
-
-- job-template:
-    name: 'fuel-merge-build-{stream}'
-
-    disabled: '{obj:disabled}'
-
-    concurrent: true
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
-        - '{installer}-defaults'
-        - fuel-project-parameter:
-            gs-pathname: '{gs-pathname}'
-
-    scm:
-        - git-scm
-
-    wrappers:
-        - ssh-agent-wrapper
-        - timeout:
-            timeout: 360
-            fail: true
-
-    triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - change-merged-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'remerge'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                    - branch-compare-type: 'ANT'
-                      branch-pattern: '**/{branch}'
-                file-paths:
-                  - compare-type: ANT
-                    pattern: 'ci/**'
-                  - compare-type: ANT
-                    pattern: 'build/**'
-                  - compare-type: ANT
-                    pattern: 'deploy/**'
-                disable-strict-forbidden-file-verification: 'true'
-                forbidden-file-paths:
-                  - compare-type: ANT
-                    pattern: 'docs/**'
-
-    builders:
-        - shell:
-            !include-raw-escape: ./fuel-build.sh
-        - shell:
-            !include-raw-escape: ./fuel-upload-artifact.sh
-        - shell:
-            !include-raw-escape: ./fuel-workspace-cleanup.sh
-
-- job-template:
-    name: 'fuel-merge-deploy-virtual-{stream}'
-
-    disabled: true
-
-    concurrent: true
-
-    properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 2
-            max-per-node: 1
-            option: 'project'
-        - build-blocker:
-            use-build-blocker: true
-            blocking-jobs:
-                - 'fuel-os-.*?-virtual-daily-.*'
-                - 'fuel-merge-deploy-virtual-.*'
-            block-level: 'NODE'
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'fuel-virtual-defaults':
-            installer: '{installer}'
-        - '{installer}-defaults'
-        - fuel-project-parameter:
-            gs-pathname: '{gs-pathname}'
-    scm:
-        - git-scm
-
-    wrappers:
-        - ssh-agent-wrapper
-
-    triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - change-merged-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'remerge'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                    - branch-compare-type: 'ANT'
-                      branch-pattern: '**/{branch}'
-                file-paths:
-                  - compare-type: ANT
-                    pattern: 'ci/**'
-                  - compare-type: ANT
-                    pattern: 'build/**'
-                  - compare-type: ANT
-                    pattern: 'deploy/**'
-                disable-strict-forbidden-file-verification: 'true'
-                forbidden-file-paths:
-                  - compare-type: ANT
-                    pattern: 'docs/**'
-            dependency-jobs: 'fuel-merge-build-{stream}'
-
-    builders:
-        - shell:
-            !include-raw-escape: ./fuel-download-artifact.sh
-        - shell:
-            !include-raw-escape: ./fuel-deploy.sh
-        - shell:
-            !include-raw-escape: ./fuel-workspace-cleanup.sh
-
-    publishers:
-        - email:
-            recipients: fzhadaev@mirantis.com
-
 - job-template:
     name: 'fuel-deploy-generic-daily-{stream}'
 
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - '{installer}-defaults'
+        - '{installer}-defaults':
+            gs-pathname: '{gs-pathname}'
         - string:
             name: GIT_BASE
             default: https://gerrit.opnfv.org/gerrit/$PROJECT
             description: 'Git URL to use on this Jenkins Slave'
         - string:
             name: DEPLOY_SCENARIO
-            default: 'os-odl_l2-nofeature-ha'
+            default: 'os-odl-nofeature-ha'
         - node:
             name: SLAVE_NAME
             description: 'Slave name on Jenkins'
                 - ericsson-pod1
             default-slaves:
                 - ericsson-pod2
-        - fuel-project-parameter:
-            gs-pathname: '{gs-pathname}'
 
     scm:
         - git-scm
             name: '$BUILD_NUMBER - POD: $NODE_NAME Scenario: $DEPLOY_SCENARIO'
 
     builders:
-        - shell:
-            !include-raw-escape: ./fuel-download-artifact.sh
         - shell:
             !include-raw-escape: ./fuel-deploy.sh
-
-########################
-# parameter macros
-########################
-- parameter:
-    name: fuel-project-parameter
-    parameters:
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
-        - string:
-            name: CACHE_DIRECTORY
-            default: $HOME/opnfv/cache/$INSTALLER_TYPE
-            description: "Directory where the cache to be used during the build is located."
-        - string:
-            name: GS_URL
-            default: artifacts.opnfv.org/$PROJECT{gs-pathname}
-            description: "URL to Google Storage."
diff --git a/jjb/fuel/fuel-upload-artifact.sh b/jjb/fuel/fuel-upload-artifact.sh
deleted file mode 100755 (executable)
index d1ac350..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o pipefail
-
-# check if we built something
-if [ -f $WORKSPACE/.noupload ]; then
-    echo "Nothing new to upload. Exiting."
-    /bin/rm -f $WORKSPACE/.noupload
-    exit 0
-fi
-
-# source the opnfv.properties to get ARTIFACT_VERSION
-source $WORKSPACE/opnfv.properties
-
-nfsstore () {
-# storing ISOs for verify & merge jobs will be done once we get the disk array
-if [[ ! "$JOB_NAME" =~ (verify|merge) ]]; then
-    # store ISO locally on NFS first
-    ISOSTORE="/iso_mount/opnfv_ci/${BRANCH##*/}"
-    if [[ -d "$ISOSTORE" ]]; then
-        # remove all but most recent 5 ISOs first to keep iso_mount clean & tidy
-        cd $ISOSTORE
-        ls -tp | grep -v '/' | tail -n +6 | xargs -d '\n' /bin/rm -f --
-
-        # store ISO
-        echo "Storing $INSTALLER_TYPE artifact on NFS..."
-        /bin/cp -f $BUILD_DIRECTORY/opnfv-$OPNFV_ARTIFACT_VERSION.iso \
-            $ISOSTORE/opnfv-$OPNFV_ARTIFACT_VERSION.iso
-    fi
-fi
-}
-
-importkey () {
-# clone releng repository
-echo "Cloning releng repository..."
-[ -d releng ] && rm -rf releng
-git clone https://gerrit.opnfv.org/gerrit/releng $WORKSPACE/releng/ &> /dev/null
-#this is where we import the siging key
-if [ -f $WORKSPACE/releng/utils/gpg_import_key.sh ]; then
-  source $WORKSPACE/releng/utils/gpg_import_key.sh
-fi
-}
-
-signiso () {
-gpg2 -vvv --batch --yes --no-tty \
-  --default-key opnfv-helpdesk@rt.linuxfoundation.org  \
-  --passphrase besteffort \
-  --detach-sig $BUILD_DIRECTORY/opnfv-$OPNFV_ARTIFACT_VERSION.iso
-
-gsutil cp $BUILD_DIRECTORY/opnfv-$OPNFV_ARTIFACT_VERSION.iso.sig gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso.sig
-echo "ISO signature Upload Complete!"
-}
-
-uploadiso () {
-# log info to console
-echo "Uploading $INSTALLER_TYPE artifact. This could take some time..."
-echo
-
-cd $WORKSPACE
-# upload artifact and additional files to google storage
-gsutil cp $BUILD_DIRECTORY/opnfv-$OPNFV_ARTIFACT_VERSION.iso \
-    gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso > gsutil.iso.log 2>&1
-gsutil cp $WORKSPACE/opnfv.properties \
-    gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.properties > gsutil.properties.log 2>&1
-if [[ ! "$JOB_NAME" =~ (verify|merge) ]]; then
-    gsutil cp $WORKSPACE/opnfv.properties \
-    gs://$GS_URL/latest.properties > gsutil.latest.log 2>&1
-elif [[ "$JOB_NAME" =~ "merge" ]]; then
-    echo "Uploaded Fuel ISO for a merged change"
-fi
-
-gsutil -m setmeta \
-    -h "Content-Type:text/html" \
-    -h "Cache-Control:private, max-age=0, no-transform" \
-    gs://$GS_URL/latest.properties \
-    gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.properties > /dev/null 2>&1
-
-gsutil -m setmeta \
-    -h "Cache-Control:private, max-age=0, no-transform" \
-    gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso > /dev/null 2>&1
-
-# disabled errexit due to gsutil setmeta complaints
-#   BadRequestException: 400 Invalid argument
-# check if we uploaded the file successfully to see if things are fine
-gsutil ls gs://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso > /dev/null 2>&1
-if [[ $? -ne 0 ]]; then
-    echo "Problem while uploading artifact!"
-    echo "Check log $WORKSPACE/gsutil.iso.log on the machine where this build is done."
-    exit 1
-fi
-
-echo "Done!"
-echo
-echo "--------------------------------------------------------"
-echo
-echo "Artifact is available as http://$GS_URL/opnfv-$OPNFV_ARTIFACT_VERSION.iso"
-echo
-echo "--------------------------------------------------------"
-echo
-}
-
-nfsstore
-
-if [[ "$JOB_NAME" =~ merge ]]; then
-    uploadiso
-elif [[ "$JOB_NAME" =~ build ]]; then
-    importkey
-    signiso
-    uploadiso
-fi
-
index 549f7da..45197fc 100644 (file)
             branch: '{stream}'
             gs-pathname: ''
             disabled: false
-        - danube:
+        - euphrates:
             branch: 'stable/{stream}'
             gs-pathname: '/{stream}'
-            disabled: false
+            disabled: true
 #####################################
 # patch verification phases
 #####################################
     phase:
         - 'basic':
-            slave-label: 'opnfv-build-ubuntu'
-        - 'build':
-            slave-label: 'opnfv-build-ubuntu'
+            slave-label: 'fuel-virtual'
         - 'deploy-virtual':
-            slave-label: 'opnfv-build-ubuntu'
+            slave-label: 'fuel-virtual'
         - 'smoke-test':
-            slave-label: 'opnfv-build-ubuntu'
+            slave-label: 'fuel-virtual'
 #####################################
 # jobs
 #####################################
             enabled: true
             max-total: 4
             option: 'project'
+        - build-blocker:
+            use-build-blocker: true
+            blocking-jobs:
+                - 'fuel-os-.*?-virtual-daily-.*'
+            block-level: 'NODE'
 
     scm:
         - git-scm-gerrit
@@ -85,9 +88,7 @@
                   - compare-type: ANT
                     pattern: 'ci/**'
                   - compare-type: ANT
-                    pattern: 'build/**'
-                  - compare-type: ANT
-                    pattern: 'deploy/**'
+                    pattern: 'mcp/**'
                 disable-strict-forbidden-file-verification: 'true'
                 forbidden-file-paths:
                   - compare-type: ANT
@@ -98,8 +99,9 @@
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
-        - 'fuel-verify-defaults':
+        - 'fuel-virtual-defaults':
+            installer: '{installer}'
+        - '{installer}-defaults':
             gs-pathname: '{gs-pathname}'
 
     builders:
                   node-parameters: false
                   kill-phase-on: FAILURE
                   abort-all-job: true
-        - multijob:
-            name: build
-            condition: SUCCESSFUL
-            projects:
-                - name: 'fuel-verify-build-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    BRANCH=$BRANCH
-                    GERRIT_REFSPEC=$GERRIT_REFSPEC
-                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
-                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
-                  node-parameters: false
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
         - multijob:
             name: deploy-virtual
             condition: SUCCESSFUL
         - logrotate-default
         - throttle:
             enabled: true
-            max-total: 6
+            max-total: 2
+            max-per-node: 1
             option: 'project'
         - build-blocker:
             use-build-blocker: true
             project: '{project}'
             branch: '{branch}'
         - '{slave-label}-defaults'
-        - '{installer}-defaults'
-        - 'fuel-verify-defaults':
+        - 'fuel-virtual-defaults':
+            installer: '{installer}'
+        - '{installer}-defaults':
             gs-pathname: '{gs-pathname}'
 
     builders:
 
             echo "Not activated!"
 
-- builder:
-    name: 'fuel-verify-build-macro'
-    builders:
-        - shell:
-            !include-raw: ./fuel-build.sh
-        - shell:
-            !include-raw: ./fuel-workspace-cleanup.sh
-
 - builder:
     name: 'fuel-verify-deploy-virtual-macro'
     builders:
-        - shell: |
-            #!/bin/bash
-
-            echo "Not activated!"
+        - shell:
+            !include-raw: ./fuel-deploy.sh
 
 - builder:
     name: 'fuel-verify-smoke-test-macro'
             #!/bin/bash
 
             echo "Not activated!"
-#####################################
-# parameter macros
-#####################################
-- parameter:
-    name: 'fuel-verify-defaults'
-    parameters:
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
-        - string:
-            name: CACHE_DIRECTORY
-            default: $HOME/opnfv/cache/$INSTALLER_TYPE
-            description: "Directory where the cache to be used during the build is located."
-        - string:
-            name: GS_URL
-            default: artifacts.opnfv.org/$PROJECT{gs-pathname}
-            description: "URL to Google Storage."
index bd42ed8..e1563ea 100644 (file)
         branch: '{stream}'
         disabled: false
         gs-pathname: ''
-    danube: &danube
-        stream: danube
+    euphrates: &euphrates
+        stream: euphrates
         branch: 'stable/{stream}'
-        disabled: false
+        disabled: true
         gs-pathname: '/{stream}'
 #--------------------------------
 # POD, INSTALLER, AND BRANCH MAPPING
             <<: *master
         - baremetal:
             slave-label: fuel-baremetal
-            <<: *danube
+            <<: *euphrates
         - virtual:
             slave-label: fuel-virtual
-            <<: *danube
+            <<: *euphrates
 #--------------------------------
 #       scenarios
 #--------------------------------
@@ -72,6 +72,7 @@
             blocking-jobs:
                 - 'fuel-os-.*?-{pod}-daily-.*'
                 - 'fuel-os-.*?-{pod}-weekly-.*'
+                - 'fuel-verify-.*'
             block-level: 'NODE'
 
     wrappers:
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - '{installer}-defaults'
+        - '{installer}-defaults':
+            gs-pathname: '{gs-pathname}'
         - '{slave-label}-defaults':
             installer: '{installer}'
         - string:
             name: DEPLOY_SCENARIO
             default: '{scenario}'
-        - fuel-weekly-parameter:
-            gs-pathname: '{gs-pathname}'
 
     builders:
         - description-setter:
     publishers:
         - email:
             recipients: peter.barabas@ericsson.com fzhadaev@mirantis.com
+        - email-jenkins-admins-on-failure
 
 - job-template:
     name: 'fuel-deploy-{pod}-weekly-{stream}'
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - '{installer}-defaults'
+        - '{installer}-defaults':
+            gs-pathname: '{gs-pathname}'
         - '{slave-label}-defaults':
             installer: '{installer}'
         - string:
             name: DEPLOY_SCENARIO
-            default: 'os-odl_l2-nofeature-ha'
-        - fuel-weekly-parameter:
-            gs-pathname: '{gs-pathname}'
+            default: 'os-odl-nofeature-ha'
         - string:
             name: DEPLOY_TIMEOUT
             default: '150'
     builders:
         - description-setter:
             description: "Built on $NODE_NAME"
-        - shell:
-            !include-raw-escape: ./fuel-download-artifact.sh
         - shell:
             !include-raw-escape: ./fuel-deploy.sh
 
     publishers:
         - email:
             recipients: peter.barabas@ericsson.com fzhadaev@mirantis.com
+        - email-jenkins-admins-on-failure
 
 ########################
-# parameter macros
-########################
-- parameter:
-    name: fuel-weekly-parameter
-    parameters:
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
-        - string:
-            name: CACHE_DIRECTORY
-            default: $HOME/opnfv/cache/$INSTALLER_TYPE
-            description: "Directory where the cache to be used during the build is located."
-        - string:
-            name: GS_URL
-            default: artifacts.opnfv.org/$PROJECT{gs-pathname}
-            description: "URL to Google Storage."
-########################
 # trigger macros
 ########################
 #-----------------------------------------------
diff --git a/jjb/fuel/fuel-workspace-cleanup.sh b/jjb/fuel/fuel-workspace-cleanup.sh
deleted file mode 100755 (executable)
index d8948c7..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o errexit
-set -o nounset
-set -o pipefail
-
-# delete the $WORKSPACE to open some space
-/bin/rm -rf $WORKSPACE
diff --git a/jjb/functest/functest-alpine.sh b/jjb/functest/functest-alpine.sh
new file mode 100755 (executable)
index 0000000..57398fa
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/bash
+
+set -e
+set +u
+set +o pipefail
+
+[[ $CI_DEBUG == true ]] && redirect="/dev/stdout" || redirect="/dev/null"
+FUNCTEST_DIR=/home/opnfv/functest
+
+# Prepare OpenStack credentials volume
+if [[ ${INSTALLER_TYPE} == 'joid' ]]; then
+    rc_file=$LAB_CONFIG/admin-openrc
+elif [[ ${INSTALLER_TYPE} == 'compass' && ${BRANCH} == 'master' ]]; then
+    cacert_file_vol="-v ${HOME}/os_cacert:${FUNCTEST_DIR}/conf/os_cacert"
+    echo "export OS_CACERT=${FUNCTEST_DIR}/conf/os_cacert" >> ${HOME}/opnfv-openrc.sh
+    rc_file=${HOME}/opnfv-openrc.sh
+else
+    rc_file=${HOME}/opnfv-openrc.sh
+fi
+rc_file_vol="-v ${rc_file}:${FUNCTEST_DIR}/conf/openstack.creds"
+
+
+# Set iptables rule to allow forwarding return traffic for container
+if ! sudo iptables -C FORWARD -j RETURN 2> ${redirect} || ! sudo iptables -L FORWARD | awk 'NR==3' | grep RETURN 2> ${redirect}; then
+    sudo iptables -I FORWARD -j RETURN
+fi
+
+DEPLOY_TYPE=baremetal
+[[ $BUILD_TAG =~ "virtual" ]] && DEPLOY_TYPE=virt
+HOST_ARCH=$(uname -m)
+
+echo "Functest: Start Docker and prepare environment"
+
+echo "Functest: Download images that will be used by test cases"
+images_dir="${HOME}/opnfv/functest/images"
+download_script=${WORKSPACE}/functest/ci/download_images.sh
+if [[ ! -f ${download_script} ]]; then
+    # to support Danube as well
+    wget https://git.opnfv.org/functest/plain/functest/ci/download_images.sh -O ${download_script} 2> ${redirect}
+fi
+chmod +x ${download_script}
+${download_script} ${images_dir} ${DEPLOY_SCENARIO} ${HOST_ARCH} 2> ${redirect}
+
+images_vol="-v ${images_dir}:${FUNCTEST_DIR}/images"
+
+dir_result="${HOME}/opnfv/functest/results/${BRANCH##*/}"
+mkdir -p ${dir_result}
+sudo rm -rf ${dir_result}/*
+results_vol="-v ${dir_result}:${FUNCTEST_DIR}/results"
+custom_params=
+test -f ${HOME}/opnfv/functest/custom/params_${DOCKER_TAG} && custom_params=$(cat ${HOME}/opnfv/functest/custom/params_${DOCKER_TAG})
+
+envs="-e INSTALLER_TYPE=${INSTALLER_TYPE} -e INSTALLER_IP=${INSTALLER_IP} \
+    -e NODE_NAME=${NODE_NAME} -e DEPLOY_SCENARIO=${DEPLOY_SCENARIO} \
+    -e BUILD_TAG=${BUILD_TAG} -e DEPLOY_TYPE=${DEPLOY_TYPE}"
+
+if [[ ${INSTALLER_TYPE} == 'compass' && ${DEPLOY_SCENARIO} == *'os-nosdn-openo-ha'* ]]; then
+    ssh_options="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
+    openo_msb_port=${openo_msb_port:-80}
+    openo_msb_endpoint="$(sshpass -p'root' ssh 2>/dev/null $ssh_options root@${installer_ip} \
+    'mysql -ucompass -pcompass -Dcompass -e "select package_config from cluster;" \
+    | sed s/,/\\n/g | grep openo_ip | cut -d \" -f 4'):$openo_msb_port"
+
+    envs=${env}" -e OPENO_MSB_ENDPOINT=${openo_msb_endpoint}"
+fi
+
+volumes="${images_vol} ${results_vol} ${sshkey_vol} ${rc_file_vol} ${cacert_file_vol}"
+
+set +e
+
+if [ ${FUNCTEST_SUITE_NAME} == 'healthcheck' ]; then
+    tiers=(healthcheck)
+else
+    tiers=(healthcheck smoke features vnf)
+fi
+
+for tier in ${tiers[@]}; do
+    FUNCTEST_IMAGE=opnfv/functest-${tier}
+    echo "Functest: Pulling Functest Docker image ${FUNCTEST_IMAGE} ..."
+    docker pull ${FUNCTEST_IMAGE}>/dev/null
+    cmd="docker run ${envs} ${volumes} ${FUNCTEST_IMAGE}"
+    echo "Running Functest tier '${tier}'. CMD: ${cmd}"
+    ${cmd}
+done
index 8de092d..b1d7e74 100644 (file)
             slave-label: '{pod}'
             installer: apex
             <<: *master
-        - arm-pod2:
-            slave-label: '{pod}'
-            installer: fuel
-            <<: *master
-        - arm-pod3:
-            slave-label: '{pod}'
-            installer: fuel
-            <<: *master
-        - arm-pod4:
-            slave-label: '{pod}'
-            installer: fuel
-            <<: *master
-        - arm-virtual1:
-            slave-label: '{pod}'
-            installer: fuel
-            <<: *master
         - zte-pod1:
             slave-label: '{pod}'
             installer: fuel
             slave-label: '{pod}'
             installer: fuel
             <<: *danube
-        - arm-pod2:
-            slave-label: '{pod}'
-            installer: fuel
-            <<: *danube
-        - arm-pod3:
-            slave-label: '{pod}'
-            installer: fuel
-            <<: *danube
-        - arm-pod4:
-            slave-label: '{pod}'
-            installer: fuel
-            <<: *danube
-        - arm-virtual1:
-            slave-label: '{pod}'
-            installer: fuel
-            <<: *danube
 # PODs for verify jobs triggered by each patch upload
-        - ool-virtual1:
-            slave-label: '{pod}'
-            installer: apex
-            <<: *master
+#        - ool-virtual1:
+#            slave-label: '{pod}'
+#            installer: apex
+#            <<: *master
 #--------------------------------
 
+    alpine-pod:
+        - ericsson-virtual-pod1bl01:
+            slave-label: '{alpine-pod}'
+            installer: fuel
+            <<: *master
+        - huawei-virtual5:
+            slave-label: '{alpine-pod}'
+            installer: compass
+            <<: *master
+
     testsuite:
         - 'suite':
             job-timeout: 60
 
     jobs:
         - 'functest-{installer}-{pod}-{testsuite}-{stream}'
+        - 'functest-alpine-{installer}-{alpine-pod}-{testsuite}-{stream}'
 
 ################################
 # job template
             description: "Built on $NODE_NAME"
         - 'functest-{testsuite}-builder'
 
+- job-template:
+    name: 'functest-alpine-{installer}-{alpine-pod}-{testsuite}-{stream}'
+
+    concurrent: true
+
+    properties:
+        - logrotate-default
+        - throttle:
+            enabled: true
+            max-per-node: 1
+            option: 'project'
+
+    wrappers:
+        - build-name:
+            name: '$BUILD_NUMBER Suite: $FUNCTEST_SUITE_NAME Scenario: $DEPLOY_SCENARIO'
+        - timeout:
+            timeout: '{job-timeout}'
+            abort: true
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - '{installer}-defaults'
+        - '{slave-label}-defaults'
+        - 'functest-{testsuite}-parameter'
+        - string:
+            name: DEPLOY_SCENARIO
+            default: 'os-nosdn-nofeature-noha'
+        - functest-parameter:
+            gs-pathname: '{gs-pathname}'
+
+    scm:
+        - git-scm
+
+    builders:
+        - description-setter:
+            description: "Built on $NODE_NAME"
+        - 'functest-alpine-daily-builder'
+
 ########################
 # parameter macros
 ########################
     name: functest-daily-builder
     builders:
         - 'functest-cleanup'
-        - 'set-functest-env'
+        - 'set-functest-env-alpine'
         - 'functest-daily'
         - 'functest-store-results'
-        - 'functest-exit'
 
 - builder:
     name: functest-suite-builder
         - 'functest-store-results'
         - 'functest-exit'
 
+- builder:
+    name: functest-alpine-daily-builder
+    builders:
+        - shell:
+            !include-raw:
+                - ./functest-env-presetup.sh
+                - ../../utils/fetch_os_creds.sh
+                - ./functest-alpine.sh
+                - ../../utils/push-test-logs.sh
+
 - builder:
     name: functest-daily
     builders:
         - shell:
-            !include-raw: ./functest-loop.sh
+            !include-raw: ./functest-alpine.sh
 
 
 - builder:
                 - ../../utils/fetch_os_creds.sh
                 - ./set-functest-env.sh
 
+- builder:
+    name: set-functest-env-alpine
+    builders:
+        - shell:
+            !include-raw:
+                - ./functest-env-presetup.sh
+                - ../../utils/fetch_os_creds.sh
+
 - builder:
     name: functest-store-results
     builders:
index a590d9f..00a5f13 100755 (executable)
@@ -2,7 +2,11 @@
 set +e
 
 [[ "$PUSH_RESULTS_TO_DB" == "true" ]] && flags+="-r"
-cmd="run_tests -t all ${flags}"
+if [ "$BRANCH" == 'master' ]; then
+    cmd="run_tests -t all ${flags}"
+else
+    cmd="python ${FUNCTEST_REPO_DIR}/functest/ci/run_tests.py -t all ${flags}"
+fi
 
 container_id=$(docker ps -a | grep opnfv/functest | awk '{print $1}' | head -1)
 docker exec $container_id $cmd
index 7036f20..c25e4ab 100644 (file)
@@ -9,6 +9,8 @@
 
     jobs:
         - 'functest-verify-{stream}'
+        - 'functest-verify-{phase}-{stream}'
+        - 'functest-docs-upload-{stream}'
 
     stream:
         - master:
         - danube:
             branch: 'stable/{stream}'
             gs-pathname: '/{stream}'
-            disabled: false
+            disabled: true
+
+    phase:
+        - 'unit-tests-and-docs':
+            slave-label: 'opnfv-build-ubuntu'
+        - 'build-x86_64':
+            slave-label: 'opnfv-build-ubuntu'
+        - 'build-aarch64':
+            slave-label: 'opnfv-build-ubuntu-arm'
 
 - job-template:
     name: 'functest-verify-{stream}'
 
     disabled: '{obj:disabled}'
 
+    project-type: 'multijob'
+
     parameters:
         - project-parameter:
             project: '{project}'
     scm:
         - git-scm-gerrit
 
+    triggers:
+        - 'functest-verify-triggers-macro':
+            project: '{project}'
+            branch: '{branch}'
+
+    builders:
+        - shell: |
+            #!/bin/bash
+            # we do nothing here as the main stuff will be done
+            # in phase jobs
+            echo "Triggering phase jobs!"
+        - multijob:
+            name: 'functest-build-and-unittest'
+            execution-type: PARALLEL
+            projects:
+                - name: 'functest-verify-unit-tests-and-docs-{stream}'
+                  current-parameters: false
+                  predefined-parameters: |
+                    GERRIT_BRANCH=$GERRIT_BRANCH
+                    GERRIT_REFSPEC=$GERRIT_REFSPEC
+                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
+                  git-revision: true
+                  node-parameters: false
+                  kill-phase-on: FAILURE
+                  abort-all-job: false
+                - name: 'functest-verify-build-x86_64-{stream}'
+                  current-parameters: false
+                  predefined-parameters: |
+                    GERRIT_BRANCH=$GERRIT_BRANCH
+                    GERRIT_REFSPEC=$GERRIT_REFSPEC
+                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
+                    ARCH=x86_64
+                  git-revision: true
+                  node-parameters: false
+                  kill-phase-on: FAILURE
+                  abort-all-job: false
+                - name: 'functest-verify-build-aarch64-{stream}'
+                  current-parameters: false
+                  predefined-parameters: |
+                    GERRIT_BRANCH=$GERRIT_BRANCH
+                    GERRIT_REFSPEC=$GERRIT_REFSPEC
+                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
+                    ARCH=aarch64
+                  git-revision: true
+                  node-parameters: false
+                  kill-phase-on: FAILURE
+                  abort-all-job: false
+
+- job-template:
+    name: 'functest-verify-{phase}-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    wrappers:
+        - ssh-agent-wrapper
+        - build-timeout:
+            timeout: 30
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - '{slave-label}-defaults'
+
+    scm:
+        - git-scm-gerrit
+
+    builders:
+        - 'functest-verify-{phase}-builders-macro'
+
+    publishers:
+        - 'functest-verify-{phase}-publishers-macro'
+
+- job-template:
+    name: 'functest-docs-upload-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - 'opnfv-build-ubuntu-defaults'
+
+    scm:
+        - git-scm
+
+    triggers:
+        - 'functest-docs-upload-triggers-macro':
+            project: '{project}'
+            branch: '{branch}'
+
+    builders:
+        - functest-upload-doc-artifact
+
+################################
+# job triggers
+################################
+- trigger:
+    name: 'functest-verify-triggers-macro'
     triggers:
         - gerrit:
             server-name: 'gerrit.opnfv.org'
                 forbidden-file-paths:
                   - compare-type: ANT
                     pattern: 'docs/**|.gitignore'
+- trigger:
+    name: 'functest-docs-upload-triggers-macro'
+    triggers:
+        - gerrit:
+            server-name: 'gerrit.opnfv.org'
+            trigger-on:
+                - change-merged-event
+                - comment-added-contains-event:
+                    comment-contains-value: 'remerge'
+            projects:
+              - project-compare-type: 'ANT'
+                project-pattern: '{project}'
+                branches:
+                  - branch-compare-type: 'ANT'
+                    branch-pattern: '**/{branch}'
+                disable-strict-forbidden-file-verification: 'true'
+                forbidden-file-paths:
+                  - compare-type: ANT
+                    pattern: 'docs/**|.gitignore'
+################################
+# job builders
+################################
 
+- builder:
+    name: 'functest-verify-unit-tests-and-docs-builders-macro'
     builders:
-        - functest-unit-tests-and-docs-build
-
+        - shell: |
+            cd $WORKSPACE && tox
+- builder:
+    name: 'functest-verify-build-x86_64-builders-macro'
+    builders:
+        - shell: |
+            echo "Not activated!"
+- builder:
+    name: 'functest-verify-build-aarch64-builders-macro'
+    builders:
+        - shell: |
+            echo "Not activated!"
+- builder:
+    name: 'functest-upload-doc-artifact'
+    builders:
+        - shell: |
+            cd $WORKSPACE && tox -edocs
+            wget -O - https://git.opnfv.org/releng/plain/utils/upload-artifact.sh | bash -s "api/_build" "docs"
+################################
+# job publishers
+################################
+- publisher:
+    name: 'functest-verify-unit-tests-and-docs-publishers-macro'
     publishers:
         - junit:
             results: nosetests.xml
                     healthy: 50
                     unhealthy: 40
                     failing: 30
-
-################################
-# job builders
-################################
-
-- builder:
-    name: functest-unit-tests-and-docs-build
-    builders:
-        - shell: |
-            cd $WORKSPACE && tox
+        - email-jenkins-admins-on-failure
+- publisher:
+    name: 'functest-verify-build-x86_64-publishers-macro'
+    publishers:
+        - email-jenkins-admins-on-failure
+- publisher:
+    name: 'functest-verify-build-aarch64-publishers-macro'
+    publishers:
+        - email-jenkins-admins-on-failure
index 469a577..9b7f135 100755 (executable)
@@ -10,7 +10,11 @@ global_ret_val=0
 
 tests=($(echo $FUNCTEST_SUITE_NAME | tr "," "\n"))
 for test in ${tests[@]}; do
-    cmd="run_tests -t $test"
+    if [ "$BRANCH" == 'master' ]; then
+        cmd="run_tests -t $test"
+    else
+        cmd="python /home/opnfv/repos/functest/functest/ci/run_tests.py -t $test"
+    fi
     docker exec $container_id $cmd
     let global_ret_val+=$?
 done
index 01cab5e..bb79dac 100755 (executable)
@@ -6,11 +6,20 @@ set +o pipefail
 
 [[ $CI_DEBUG == true ]] && redirect="/dev/stdout" || redirect="/dev/null"
 
+DEPLOY_TYPE=baremetal
+[[ $BUILD_TAG =~ "virtual" ]] && DEPLOY_TYPE=virt
+HOST_ARCH=$(uname -m)
+
 # Prepare OpenStack credentials volume
+rc_file_vol="-v ${HOME}/opnfv-openrc.sh:/home/opnfv/functest/conf/openstack.creds"
+
 if [[ ${INSTALLER_TYPE} == 'joid' ]]; then
     rc_file_vol="-v $LAB_CONFIG/admin-openrc:/home/opnfv/functest/conf/openstack.creds"
-else
-    rc_file_vol="-v ${HOME}/opnfv-openrc.sh:/home/opnfv/functest/conf/openstack.creds"
+elif [[ ${INSTALLER_TYPE} == 'compass' && ${BRANCH} == 'master' ]]; then
+    cacert_file_vol="-v ${HOME}/os_cacert:/home/opnfv/functest/conf/os_cacert"
+    echo "export OS_CACERT=/home/opnfv/functest/conf/os_cacert" >> ${HOME}/opnfv-openrc.sh
+elif [[ ${INSTALLER_TYPE} == 'fuel' && ${DEPLOY_TYPE} == 'baremetal' ]]; then
+    cacert_file_vol="-v ${HOME}/os_cacert:/etc/ssl/certs/mcp_os_cacert"
 fi
 
 
@@ -19,17 +28,15 @@ if ! sudo iptables -C FORWARD -j RETURN 2> ${redirect} || ! sudo iptables -L FOR
     sudo iptables -I FORWARD -j RETURN
 fi
 
-DEPLOY_TYPE=baremetal
-[[ $BUILD_TAG =~ "virtual" ]] && DEPLOY_TYPE=virt
-
 echo "Functest: Start Docker and prepare environment"
 
 if [ "$BRANCH" != 'stable/danube' ]; then
   echo "Functest: Download images that will be used by test cases"
   images_dir="${HOME}/opnfv/functest/images"
   chmod +x ${WORKSPACE}/functest/ci/download_images.sh
-  ${WORKSPACE}/functest/ci/download_images.sh ${images_dir} 2> ${redirect}
+  ${WORKSPACE}/functest/ci/download_images.sh ${images_dir} > ${redirect}
   images_vol="-v ${images_dir}:/home/opnfv/functest/images"
+  echo "Functest: Images successfully downloaded"
 fi
 
 dir_result="${HOME}/opnfv/functest/results/${BRANCH##*/}"
@@ -38,13 +45,21 @@ sudo rm -rf ${dir_result}/*
 results_vol="-v ${dir_result}:/home/opnfv/functest/results"
 custom_params=
 test -f ${HOME}/opnfv/functest/custom/params_${DOCKER_TAG} && custom_params=$(cat ${HOME}/opnfv/functest/custom/params_${DOCKER_TAG})
+echo "Functest: custom parameters successfully retrieved: ${custom_params}"
 
 envs="-e INSTALLER_TYPE=${INSTALLER_TYPE} -e INSTALLER_IP=${INSTALLER_IP} \
     -e NODE_NAME=${NODE_NAME} -e DEPLOY_SCENARIO=${DEPLOY_SCENARIO} \
     -e BUILD_TAG=${BUILD_TAG} -e CI_DEBUG=${CI_DEBUG} -e DEPLOY_TYPE=${DEPLOY_TYPE}"
 
+ssh_options="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
+
+if [ "${INSTALLER_TYPE}" == 'fuel' ] && [ "$BRANCH" != 'stable/danube' ]; then
+    COMPUTE_ARCH=$(ssh -l ubuntu ${INSTALLER_IP} -i ${SSH_KEY} ${ssh_options} \
+        "sudo salt 'cmp*' grains.get cpuarch --out yaml | awk '{print \$2; exit}'")
+    envs="${envs} -e POD_ARCH=${COMPUTE_ARCH}"
+fi
+
 if [[ ${INSTALLER_TYPE} == 'compass' && ${DEPLOY_SCENARIO} == *'os-nosdn-openo-ha'* ]]; then
-    ssh_options="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
     openo_msb_port=${openo_msb_port:-80}
     openo_msb_endpoint="$(sshpass -p'root' ssh 2>/dev/null $ssh_options root@${installer_ip} \
     'mysql -ucompass -pcompass -Dcompass -e "select package_config from cluster;" \
@@ -54,12 +69,13 @@ if [[ ${INSTALLER_TYPE} == 'compass' && ${DEPLOY_SCENARIO} == *'os-nosdn-openo-h
 fi
 
 if [ "$BRANCH" != 'stable/danube' ]; then
-  volumes="${images_vol} ${results_vol} ${sshkey_vol} ${stackrc_vol} ${rc_file_vol}"
+  volumes="${images_vol} ${results_vol} ${sshkey_vol} ${stackrc_vol} ${rc_file_vol} ${cacert_file_vol}"
 else
   volumes="${results_vol} ${sshkey_vol} ${stackrc_vol} ${rc_file_vol}"
 fi
 
-HOST_ARCH=$(uname -m)
+echo "Functest: volumes defined"
+
 FUNCTEST_IMAGE="opnfv/functest"
 if [ "$HOST_ARCH" = "aarch64" ]; then
     FUNCTEST_IMAGE="${FUNCTEST_IMAGE}_${HOST_ARCH}"
@@ -90,7 +106,12 @@ if [ $(docker ps | grep "${FUNCTEST_IMAGE}:${DOCKER_TAG}" | wc -l) == 0 ]; then
     exit 1
 fi
 
-cmd="prepare_env start"
+if [ "$BRANCH" == 'master' ]; then
+    cmd="prepare_env start"
+else
+    cmd="python ${FUNCTEST_REPO_DIR}/functest/ci/prepare_env.py start"
+fi
+
 
 echo "Executing command inside the docker: ${cmd}"
 docker exec ${container_id} ${cmd}
index ee154af..8c01a9f 100644 (file)
+---
 - parameter:
     name: 'apex-defaults'
     parameters:
-        - string:
-            name: INSTALLER_IP
-            default: '192.168.X.X'
-            description: 'IP of the installer'
-        - string:
-            name: INSTALLER_TYPE
-            default: apex
-            description: 'Installer used for deploying OPNFV on this POD'
-        - string:
-            name: EXTERNAL_NETWORK
-            default: 'external'
-            description: 'external network for test'
+      - string:
+          name: INSTALLER_IP
+          default: '192.168.X.X'
+          description: 'IP of the installer'
+      - string:
+          name: INSTALLER_TYPE
+          default: apex
+          description: 'Installer used for deploying OPNFV on this POD'
+      - string:
+          name: EXTERNAL_NETWORK
+          default: 'external'
+          description: 'external network for test'
 
 - parameter:
     name: 'compass-defaults'
     parameters:
-        - string:
-            name: INSTALLER_IP
-            default: '192.168.200.2'
-            description: 'IP of the installer'
-        - string:
-            name: INSTALLER_TYPE
-            default: compass
-            description: 'Installer used for deploying OPNFV on this POD'
-        - string:
-            name: EXTERNAL_NETWORK
-            default: 'ext-net'
-            description: 'external network for test'
+      - string:
+          name: INSTALLER_IP
+          default: '192.168.200.2'
+          description: 'IP of the installer'
+      - string:
+          name: INSTALLER_TYPE
+          default: compass
+          description: 'Installer used for deploying OPNFV on this POD'
+      - string:
+          name: EXTERNAL_NETWORK
+          default: 'ext-net'
+          description: 'external network for test'
 
 - parameter:
     name: 'fuel-defaults'
     parameters:
-        - string:
-            name: INSTALLER_IP
-            default: '10.20.0.2'
-            description: 'IP of the installer'
-        - string:
-            name: SALT_MASTER_IP
-            default: '192.168.10.100'
-            description: 'IP of the salt master (for mcp deployments)'
-        - string:
-            name: SSH_KEY
-            default: '/tmp/mcp.rsa'
-            description: 'Path to private SSH key to access environment nodes'
-        - string:
-            name: INSTALLER_TYPE
-            default: fuel
-            description: 'Installer used for deploying OPNFV on this POD'
-        - string:
-            name: EXTERNAL_NETWORK
-            default: 'admin_floating_net'
-            description: 'external network for test'
-        - string:
-            name: BRIDGE
-            default: 'pxebr'
-            description: 'pxe bridge for booting of Fuel master'
+      - string:
+          name: INSTALLER_IP
+          default: '10.20.0.2'
+          description: 'IP of the installer'
+      - string:
+          name: SSH_KEY
+          default: "/var/lib/opnfv/mcp.rsa"
+          description: 'Path to private SSH key to access environment nodes'
+      - string:
+          name: INSTALLER_TYPE
+          default: fuel
+          description: 'Installer used for deploying OPNFV on this POD'
+      - string:
+          name: EXTERNAL_NETWORK
+          default: 'admin_floating_net'
+          description: 'external network for test'
+      - string:
+          name: BRIDGE
+          default: 'pxebr'
+          description: 'Bridge(s) to be used by salt master'
+      - string:
+          name: GS_URL
+          default: '$GS_BASE{gs-pathname}'
+          description: "URL to Google Storage."
 
 - parameter:
     name: 'joid-defaults'
     parameters:
-        - string:
-            name: INSTALLER_IP
-            default: '192.168.122.5'
-            description: 'IP of the installer'
-        - string:
-            name: INSTALLER_TYPE
-            default: joid
-            description: 'Installer used for deploying OPNFV on this POD'
-        - string:
-            name: MODEL
-            default: 'os'
-            description: 'Model to deploy (os|k8)'
-        - string:
-            name: OS_RELEASE
-            default: 'newton'
-            description: 'OpenStack release (mitaka|newton)'
-        - string:
-            name: EXTERNAL_NETWORK
-            default: ext-net
-            description: "External network used for Floating ips."
-        - string:
-            name: LAB_CONFIG
-            default: "$HOME/joid_config"
-            description: "Local lab config and Openstack openrc location"
-        - string:
-            name: MAAS_REINSTALL
-            default: 'false'
-            description: "Reinstall MAAS and Bootstrap before deploy [true/false]"
-        - string:
-            name: UBUNTU_DISTRO
-            default: 'xenial'
-            description: "Ubuntu distribution to use for Openstack (xenial)"
-        - string:
-            name: CPU_ARCHITECTURE
-            default: 'amd64'
-            description: "CPU Architecture to use for Ubuntu distro "
+      - string:
+          name: INSTALLER_IP
+          default: '192.168.122.5'
+          description: 'IP of the installer'
+      - string:
+          name: INSTALLER_TYPE
+          default: joid
+          description: 'Installer used for deploying OPNFV on this POD'
+      - string:
+          name: MODEL
+          default: 'os'
+          description: 'Model to deploy (os|k8)'
+      - string:
+          name: OS_RELEASE
+          default: 'ocata'
+          description: 'OpenStack release (mitaka|newton|ocata)'
+      - string:
+          name: EXTERNAL_NETWORK
+          default: ext-net
+          description: "External network used for Floating ips."
+      - string:
+          name: LAB_CONFIG
+          default: "$HOME/joid_config"
+          description: "Local lab config and Openstack openrc location"
+      - string:
+          name: MAAS_REINSTALL
+          default: 'false'
+          description: "Reinstall MAAS and Bootstrap before deploy [true/false]"
+      - string:
+          name: UBUNTU_DISTRO
+          default: 'xenial'
+          description: "Ubuntu distribution to use for Openstack (xenial)"
+      - string:
+          name: CPU_ARCHITECTURE
+          default: 'amd64'
+          description: "CPU Architecture to use for Ubuntu distro "
 
 - parameter:
     name: 'daisy-defaults'
     parameters:
-        - string:
-            name: INSTALLER_IP
-            default: '10.20.7.3'
-            description: 'IP of the installer'
-        - string:
-            name: INSTALLER_TYPE
-            default: daisy
-            description: 'Installer used for deploying OPNFV on this POD'
-        - string:
-            name: BRIDGE
-            default: 'br7'
-            description: 'pxe bridge for booting of Fuel master'
+      - string:
+          name: INSTALLER_IP
+          default: '10.20.7.3'
+          description: 'IP of the installer'
+      - string:
+          name: INSTALLER_TYPE
+          default: daisy
+          description: 'Installer used for deploying OPNFV on this POD'
+      - string:
+          name: BRIDGE
+          default: 'br7'
+          description: 'pxe bridge for booting of Daisy master'
 
 - parameter:
     name: 'infra-defaults'
     parameters:
-        - string:
-            name: INSTALLER_IP
-            default: '192.168.122.2'
-            description: 'IP of the installer'
-        - string:
-            name: INSTALLER_TYPE
-            default: infra
-            description: 'Installer used for deploying OPNFV on this POD'
+      - string:
+          name: INSTALLER_IP
+          default: '192.168.122.2'
+          description: 'IP of the installer'
+      - string:
+          name: INSTALLER_TYPE
+          default: infra
+          description: 'Installer used for deploying OPNFV on this POD'
+
 - parameter:
     name: 'netvirt-defaults'
     parameters:
-        - string:
-            name: INSTALLER_IP
-            default: '192.168.X.X'
-            description: 'IP of the installer'
-        - string:
-            name: INSTALLER_TYPE
-            default: apex
-            description: 'Installer used for deploying OPNFV on this POD'
-        - string:
-            name: EXTERNAL_NETWORK
-            default: 'external'
-            description: 'external network for test'
+      - string:
+          name: INSTALLER_IP
+          default: '192.168.X.X'
+          description: 'IP of the installer'
+      - string:
+          name: INSTALLER_TYPE
+          default: apex
+          description: 'Installer used for deploying OPNFV on this POD'
+      - string:
+          name: EXTERNAL_NETWORK
+          default: 'external'
+          description: 'external network for test'
index 2838886..2e94767 100644 (file)
@@ -1,14 +1,22 @@
+---
 # jjb defaults
 
 - defaults:
     name: global
 
     wrappers:
-        - ssh-agent-wrapper
+      - ssh-agent-wrapper
 
     project-type: freestyle
 
     node: master
 
     properties:
-        - logrotate-default
+      - logrotate-default
+
+    publishers:
+      # Any project that has a publisher will not have this macro
+      # included due to the nature of JJB defaults. Projects will have
+      # to explicitly add this macro to their list of publishers in
+      # order for emails to be sent.
+      - email-jenkins-admins-on-failure
index e4dfa8d..59415f5 100644 (file)
@@ -1,3 +1,4 @@
+---
 # Releng macros
 #
 # NOTE: make sure macros are listed in execution ordered.
 - parameter:
     name: project-parameter
     parameters:
-        - string:
-            name: PROJECT
-            default: '{project}'
-            description: "JJB configured PROJECT parameter to identify an opnfv Gerrit project"
-        - string:
-            name: GS_BASE
-            default: artifacts.opnfv.org/$PROJECT
-            description: "URL to Google Storage."
-        - string:
-            name: GS_BASE_PROXY
-            default: build.opnfv.org/artifacts.opnfv.org/$PROJECT
-            description: "URL to Google Storage proxy"
-        - string:
-            name: BRANCH
-            default: '{branch}'
-            description: "JJB configured BRANCH parameter (e.g. master, stable/danube)"
-        - string:
-            name: GERRIT_BRANCH
-            default: '{branch}'
-            description: "JJB configured GERRIT_BRANCH parameter (deprecated)"
+      - string:
+          name: PROJECT
+          default: '{project}'
+          description: "JJB configured PROJECT parameter to identify an opnfv Gerrit project"
+      - string:
+          name: GS_BASE
+          default: artifacts.opnfv.org/$PROJECT
+          description: "URL to Google Storage."
+      - string:
+          name: GS_BASE_PROXY
+          default: build.opnfv.org/artifacts.opnfv.org/$PROJECT
+          description: "URL to Google Storage proxy"
+      - string:
+          name: BRANCH
+          default: '{branch}'
+          description: "JJB configured BRANCH parameter (e.g. master, stable/danube)"
+      - string:
+          name: GERRIT_BRANCH
+          default: '{branch}'
+          description: "JJB configured GERRIT_BRANCH parameter (deprecated)"
 
 - property:
     name: logrotate-default
     properties:
-        - build-discarder:
-            days-to-keep: 60
-            num-to-keep: 200
-            artifact-days-to-keep: 60
-            artifact-num-to-keep: 200
+      - build-discarder:
+          days-to-keep: 60
+          num-to-keep: 200
+          artifact-days-to-keep: 60
+          artifact-num-to-keep: 200
 
 - scm:
     name: git-scm
     scm:
-        - git: &git-scm-defaults
-            credentials-id: '$SSH_CREDENTIAL_ID'
-            url: '$GIT_BASE'
-            branches:
-                - 'origin/$BRANCH'
-            timeout: 15
+      - git: &git-scm-defaults
+          credentials-id: '$SSH_CREDENTIAL_ID'
+          url: '$GIT_BASE'
+          branches:
+            - 'origin/$BRANCH'
+          timeout: 15
 
 - scm:
     name: git-scm-gerrit
     scm:
-        - git:
-            choosing-strategy: 'gerrit'
-            refspec: '$GERRIT_REFSPEC'
-            <<: *git-scm-defaults
+      - git:
+          choosing-strategy: 'gerrit'
+          refspec: '$GERRIT_REFSPEC'
+          <<: *git-scm-defaults
 - scm:
     name: git-scm-with-submodules
     scm:
-        - git:
-            credentials-id: '$SSH_CREDENTIAL_ID'
-            url: '$GIT_BASE'
-            refspec: ''
-            branches:
-                - 'refs/heads/{branch}'
-            skip-tag: true
-            wipe-workspace: true
-            submodule:
-                recursive: true
-                timeout: 20
+      - git:
+          credentials-id: '$SSH_CREDENTIAL_ID'
+          url: '$GIT_BASE'
+          refspec: ''
+          branches:
+            - 'refs/heads/{branch}'
+          skip-tag: true
+          wipe-workspace: true
+          submodule:
+            recursive: true
+            timeout: 20
 - trigger:
     name: 'daily-trigger-disabled'
     triggers:
-        - timed: ''
+      - timed: ''
 
 - trigger:
     name: 'weekly-trigger-disabled'
     triggers:
-        - timed: ''
+      - timed: ''
 
 - trigger:
     name: gerrit-trigger-patchset-created
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - patchset-created-event:
-                    exclude-drafts: 'false'
-                    exclude-trivial-rebase: 'false'
-                    exclude-no-code-change: 'false'
-                - draft-published-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'recheck'
-                - comment-added-contains-event:
-                    comment-contains-value: 'reverify'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-                file-paths:
-                  - compare-type: 'ANT'
-                    pattern: '{files}'
-            skip-vote:
-                successful: false
-                failed: false
-                unstable: false
-                notbuilt: false
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: 'recheck'
+            - comment-added-contains-event:
+                comment-contains-value: 'reverify'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              file-paths:
+                - compare-type: 'ANT'
+                  pattern: '{files}'
+          skip-vote:
+            successful: false
+            failed: false
+            unstable: false
+            notbuilt: false
 
 - trigger:
     name: gerrit-trigger-change-merged
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - change-merged-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'remerge'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-                file-paths:
-                  - compare-type: 'ANT'
-                    pattern: '{files}'
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - change-merged-event
+            - comment-added-contains-event:
+                comment-contains-value: 'remerge'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              file-paths:
+                - compare-type: 'ANT'
+                  pattern: '{files}'
 
 - trigger:
     name: 'experimental'
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - comment-added-contains-event:
-                    comment-contains-value: 'check-experimental'
-            projects:
-                - project-compare-type: 'ANT'
-                  project-pattern: '{project}'
-                  branches:
-                      - branch-compare-type: 'ANT'
-                        branch-pattern: '**/{branch}'
-                  file-paths:
-                      - compare-type: 'ANT'
-                        pattern: 'tests/**'
-            skip-vote:
-                successful: true
-                failed: true
-                unstable: true
-                notbuilt: true
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - comment-added-contains-event:
+                comment-contains-value: 'check-experimental'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              file-paths:
+                - compare-type: 'ANT'
+                  pattern: '{files}'
+          skip-vote:
+            successful: true
+            failed: true
+            unstable: true
+            notbuilt: true
 
 - wrapper:
     name: ssh-agent-wrapper
     wrappers:
-        - ssh-agent-credentials:
-            users:
-                - 'd42411ac011ad6f3dd2e1fa34eaa5d87f910eb2e'
+      - ssh-agent-credentials:
+          users:
+            - 'd42411ac011ad6f3dd2e1fa34eaa5d87f910eb2e'
+
+- wrapper:
+    name: build-timeout
+    wrappers:
+      - timeout:
+          timeout: '{timeout}'
+          timeout-var: 'BUILD_TIMEOUT'
+          fail: true
 
 - wrapper:
     name: fix-workspace-permissions
     wrappers:
-        - pre-scm-buildstep:
+      - pre-scm-buildstep:
           - shell: |
-                #!/bin/bash
-                sudo chown -R $USER:$USER $WORKSPACE || exit 1
+             #!/bin/bash
+             sudo chown -R $USER:$USER $WORKSPACE || exit 1
 
 - builder:
     name: build-html-and-pdf-docs-output
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o xtrace
-            export PATH=$PATH:/usr/local/bin/
-            git clone ssh://gerrit.opnfv.org:29418/opnfvdocs docs_build/_opnfvdocs
-            GERRIT_COMMENT=gerrit_comment.txt ./docs_build/_opnfvdocs/scripts/docs-build.sh
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o xtrace
+          export PATH=$PATH:/usr/local/bin/
+          git clone ssh://gerrit.opnfv.org:29418/opnfvdocs docs_build/_opnfvdocs
+          GERRIT_COMMENT=gerrit_comment.txt ./docs_build/_opnfvdocs/scripts/docs-build.sh
 
 - builder:
     name: upload-under-review-docs-to-opnfv-artifacts
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o pipefail
-            set -o xtrace
-            export PATH=$PATH:/usr/local/bin/
-
-            [[ $GERRIT_CHANGE_NUMBER =~ .+ ]]
-            [[ -d docs_output ]] || exit 0
-
-            echo
-            echo "###########################"
-            echo "UPLOADING DOCS UNDER REVIEW"
-            echo "###########################"
-            echo
-
-            gs_base="artifacts.opnfv.org/$PROJECT/review"
-            gs_path="$gs_base/$GERRIT_CHANGE_NUMBER"
-            local_path="upload/$GERRIT_CHANGE_NUMBER"
-
-            mkdir -p upload
-            mv docs_output "$local_path"
-            gsutil -m cp -r "$local_path" "gs://$gs_base"
-
-            gsutil -m setmeta \
-                -h "Content-Type:text/html" \
-                -h "Cache-Control:private, max-age=0, no-transform" \
-                "gs://$gs_path"/**.html > /dev/null 2>&1
-
-            echo "Document link(s):" >> gerrit_comment.txt
-            find "$local_path" | grep -e 'index.html$' -e 'pdf$' | \
-                sed -e "s|^$local_path|    http://$gs_path|" >> gerrit_comment.txt
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o pipefail
+          set -o xtrace
+          export PATH=$PATH:/usr/local/bin/
+
+          [[ $GERRIT_CHANGE_NUMBER =~ .+ ]]
+          [[ -d docs_output ]] || exit 0
+
+          echo
+          echo "###########################"
+          echo "UPLOADING DOCS UNDER REVIEW"
+          echo "###########################"
+          echo
+
+          gs_base="artifacts.opnfv.org/$PROJECT/review"
+          gs_path="$gs_base/$GERRIT_CHANGE_NUMBER"
+          local_path="upload/$GERRIT_CHANGE_NUMBER"
+
+          mkdir -p upload
+          mv docs_output "$local_path"
+          gsutil -m cp -r "$local_path" "gs://$gs_base"
+
+          gsutil -m setmeta \
+              -h "Content-Type:text/html" \
+              -h "Cache-Control:private, max-age=0, no-transform" \
+              "gs://$gs_path"/**.html > /dev/null 2>&1
+
+          echo "Document link(s):" >> gerrit_comment.txt
+          find "$local_path" | grep -e 'index.html$' -e 'pdf$' | \
+              sed -e "s|^$local_path|    http://$gs_path|" >> gerrit_comment.txt
 
 - builder:
     name: upload-generated-docs-to-opnfv-artifacts
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o pipefail
-            set -o xtrace
-            export PATH=$PATH:/usr/local/bin/
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o pipefail
+          set -o xtrace
+          export PATH=$PATH:/usr/local/bin/
 
-            [[ -d docs_output ]] || exit 0
+          [[ -d docs_output ]] || exit 0
 
-            echo
-            echo "########################"
-            echo "UPLOADING GENERATED DOCS"
-            echo "########################"
-            echo
+          echo
+          echo "########################"
+          echo "UPLOADING GENERATED DOCS"
+          echo "########################"
+          echo
 
-            echo "gs_path="$GS_URL/docs""
-            echo "local_path="upload/docs""
+          echo "gs_path="$GS_URL/docs""
+          echo "local_path="upload/docs""
 
-            gs_path="$GS_URL/docs"
-            local_path="upload/docs"
+          gs_path="$GS_URL/docs"
+          local_path="upload/docs"
 
-            mkdir -p upload
-            mv docs_output "$local_path"
-            ls "$local_path"
+          mkdir -p upload
+          mv docs_output "$local_path"
+          ls "$local_path"
 
-            echo "gsutil -m cp -r "$local_path"/* "gs://$gs_path""
-            gsutil -m cp -r "$local_path"/* "gs://$gs_path"
+          echo "gsutil -m cp -r "$local_path"/* "gs://$gs_path""
+          gsutil -m cp -r "$local_path"/* "gs://$gs_path"
 
-            gsutil -m setmeta \
-                -h "Content-Type:text/html" \
-                -h "Cache-Control:private, max-age=0, no-transform" \
-                "gs://$gs_path"/**.html > /dev/null 2>&1
+          gsutil -m setmeta \
+              -h "Content-Type:text/html" \
+              -h "Cache-Control:private, max-age=0, no-transform" \
+              "gs://$gs_path"/**.html > /dev/null 2>&1
 
-            echo "Document link(s):" >> gerrit_comment.txt
-            find "$local_path" | grep -e 'index.html$' -e 'pdf$' | \
-                sed -e "s|^$local_path|    http://$gs_path|" >> gerrit_comment.txt
+          echo "Document link(s):" >> gerrit_comment.txt
+          find "$local_path" | grep -e 'index.html$' -e 'pdf$' | \
+              sed -e "s|^$local_path|    http://$gs_path|" >> gerrit_comment.txt
 
 # To take advantage of this macro, have your build write
 # out the file 'gerrit_comment.txt' with information to post
 - builder:
     name: report-build-result-to-gerrit
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o pipefail
-            set -o xtrace
-            export PATH=$PATH:/usr/local/bin/
-            if [[ -e gerrit_comment.txt ]] ; then
-                echo
-                echo "posting review comment to gerrit..."
-                echo
-                cat gerrit_comment.txt
-                echo
-                ssh -p 29418 gerrit.opnfv.org \
-                    "gerrit review -p $GERRIT_PROJECT \
-                     -m '$(cat gerrit_comment.txt)' \
-                     $GERRIT_PATCHSET_REVISION \
-                     --notify NONE"
-            fi
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o pipefail
+          set -o xtrace
+          export PATH=$PATH:/usr/local/bin/
+          if [[ -e gerrit_comment.txt ]] ; then
+              echo
+              echo "posting review comment to gerrit..."
+              echo
+              cat gerrit_comment.txt
+              echo
+              ssh -p 29418 gerrit.opnfv.org \
+                  "gerrit review -p $GERRIT_PROJECT \
+                   -m '$(cat gerrit_comment.txt)' \
+                   $GERRIT_PATCHSET_REVISION \
+                   --notify NONE"
+          fi
 
 - builder:
     name: remove-old-docs-from-opnfv-artifacts
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o pipefail
-            set -o xtrace
-            export PATH=$PATH:/usr/local/bin/
-
-            [[ $GERRIT_CHANGE_NUMBER =~ .+ ]]
-
-            gs_path="artifacts.opnfv.org/$PROJECT/review/$GERRIT_CHANGE_NUMBER"
-
-            if gsutil ls "gs://$gs_path" > /dev/null 2>&1 ; then
-                echo
-                echo "Deleting Out-of-dated Documents..."
-                gsutil -m rm -r "gs://$gs_path"
-            fi
-            gs_path="artifacts.opnfv.org/review/$GERRIT_CHANGE_NUMBER"
-
-            if gsutil ls "gs://$gs_path" > /dev/null 2>&1 ; then
-                echo
-                echo "Deleting Out-of-dated Documents..."
-                gsutil -m rm -r "gs://$gs_path"
-            fi
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o pipefail
+          set -o xtrace
+          export PATH=$PATH:/usr/local/bin/
+
+          [[ $GERRIT_CHANGE_NUMBER =~ .+ ]]
+
+          gs_path="artifacts.opnfv.org/$PROJECT/review/$GERRIT_CHANGE_NUMBER"
+
+          if gsutil ls "gs://$gs_path" > /dev/null 2>&1 ; then
+              echo
+              echo "Deleting Out-of-dated Documents..."
+              gsutil -m rm -r "gs://$gs_path"
+          fi
+          gs_path="artifacts.opnfv.org/review/$GERRIT_CHANGE_NUMBER"
+
+          if gsutil ls "gs://$gs_path" > /dev/null 2>&1 ; then
+              echo
+              echo "Deleting Out-of-dated Documents..."
+              gsutil -m rm -r "gs://$gs_path"
+          fi
 
 - builder:
     name: build-and-upload-artifacts-json-api
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o pipefail
-            export PATH=$PATH:/usr/local/bin/
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o pipefail
+          export PATH=$PATH:/usr/local/bin/
 
-            virtualenv -p python2.7 $WORKSPACE/releng_artifacts
-            source $WORKSPACE/releng_artifacts/bin/activate
+          virtualenv -p python2.7 $WORKSPACE/releng_artifacts
+          source $WORKSPACE/releng_artifacts/bin/activate
 
-            # install python packages
-            pip install google-api-python-client
+          # install python packages
+          pip install google-api-python-client
 
-            # generate and upload index file
-            echo "Generating Artifacts API ..."
-            python $WORKSPACE/utils/opnfv-artifacts.py > index.json
-            gsutil cp index.json gs://artifacts.opnfv.org/index.json
+          # generate and upload index file
+          echo "Generating Artifacts API ..."
+          python $WORKSPACE/utils/opnfv-artifacts.py > index.json
+          gsutil cp index.json gs://artifacts.opnfv.org/index.json
 
-            deactivate
+          deactivate
 
 - builder:
     name: lint-python-code
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o pipefail
-            set -o xtrace
-            export PATH=$PATH:/usr/local/bin/
-
-            virtualenv -p python2.7 $WORKSPACE/releng_flake8
-            source $WORKSPACE/releng_flake8/bin/activate
-
-            # install python packages
-            pip install "flake8==2.6.2"
-
-            # generate and upload lint log
-            echo "Running flake8 code on $PROJECT ..."
-
-            # Get number of flake8 violations. If none, this will be an
-            # empty string: ""
-            FLAKE_COUNT="$(find . \
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o pipefail
+          set -o xtrace
+          export PATH=$PATH:/usr/local/bin/
+
+          virtualenv -p python2.7 $WORKSPACE/releng_flake8
+          source $WORKSPACE/releng_flake8/bin/activate
+
+          # install python packages
+          pip install "flake8==2.6.2"
+
+          # generate and upload lint log
+          echo "Running flake8 code on $PROJECT ..."
+
+          # Get number of flake8 violations. If none, this will be an
+          # empty string: ""
+          FLAKE_COUNT="$(find . \
+              -path './releng_flake8' -prune -o \
+              -path './.tox' -prune -o \
+              -type f -name "*.py" -print | \
+              xargs flake8 --exit-zero -qq --count 2>&1)"
+
+          # Ensure we start with a clean environment
+          rm -f lint.log
+
+          if [ ! -z $FLAKE_COUNT ]; then
+            echo "Flake8 Violations: $FLAKE_COUNT" > lint.log
+            find . \
                 -path './releng_flake8' -prune -o \
                 -path './.tox' -prune -o \
                 -type f -name "*.py" -print | \
-                xargs flake8 --exit-zero -qq --count 2>&1)"
-
-            # Ensure we start with a clean environment
-            rm -f lint.log
-
-            if [ ! -z $FLAKE_COUNT ]; then
-              echo "Flake8 Violations: $FLAKE_COUNT" > lint.log
-              find . \
-                  -path './releng_flake8' -prune -o \
-                  -path './.tox' -prune -o \
-                  -type f -name "*.py" -print | \
-                  xargs flake8 --exit-zero --first >> violation.log
-              SHOWN=$(wc -l violation.log | cut -d' ' -f1)
-              echo -e "First $SHOWN shown\n---" >> lint.log
-              cat violation.log >> lint.log
-              sed -r -i '4,$s/^/ /g' lint.log
-              rm violation.log
-            fi
-
-            deactivate
+                xargs flake8 --exit-zero --first >> violation.log
+            SHOWN=$(wc -l violation.log | cut -d' ' -f1)
+            echo -e "First $SHOWN shown\n---" >> lint.log
+            cat violation.log >> lint.log
+            sed -r -i '4,$s/^/ /g' lint.log
+            rm violation.log
+          fi
+
+          deactivate
 
 - builder:
     name: report-lint-result-to-gerrit
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o pipefail
-            set -o xtrace
-            export PATH=$PATH:/usr/local/bin/
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o pipefail
+          set -o xtrace
+          export PATH=$PATH:/usr/local/bin/
 
-            # If no violations were found, no lint log will exist.
-            if [[ -e lint.log ]] ; then
-                echo -e "\nposting linting report to gerrit...\n"
+          # If no violations were found, no lint log will exist.
+          if [[ -e lint.log ]] ; then
+              echo -e "\nposting linting report to gerrit...\n"
 
-                cat lint.log
-                echo
+              cat lint.log
+              echo
 
-                ssh -p 29418 gerrit.opnfv.org \
-                    "gerrit review -p $GERRIT_PROJECT \
-                     -m \"$(cat lint.log)\" \
-                     $GERRIT_PATCHSET_REVISION \
-                     --notify NONE"
+              ssh -p 29418 gerrit.opnfv.org \
+                  "gerrit review -p $GERRIT_PROJECT \
+                   -m \"$(cat lint.log)\" \
+                   $GERRIT_PATCHSET_REVISION \
+                   --notify NONE"
 
-                exit 1
-            fi
+              exit 1
+          fi
 
 - builder:
     name: upload-review-docs
     builders:
-        - build-html-and-pdf-docs-output
-        - upload-under-review-docs-to-opnfv-artifacts
-        - report-build-result-to-gerrit
+      - build-html-and-pdf-docs-output
+      - upload-under-review-docs-to-opnfv-artifacts
+      - report-build-result-to-gerrit
 
 - builder:
     name: upload-merged-docs
     builders:
-        - build-html-and-pdf-docs-output
-        - upload-generated-docs-to-opnfv-artifacts
-        - report-build-result-to-gerrit
-        - remove-old-docs-from-opnfv-artifacts
+      - build-html-and-pdf-docs-output
+      - upload-generated-docs-to-opnfv-artifacts
+      - report-build-result-to-gerrit
+      - remove-old-docs-from-opnfv-artifacts
 
 - builder:
     name: check-bash-syntax
     builders:
-        - shell: "find . -name '*.sh' | xargs bash -n"
+      - shell: "find . -name '*.sh' | xargs bash -n"
 
 - builder:
     name: lint-yaml-code
     builders:
-        - shell: |
-            #!/bin/bash
-            set -o errexit
-            set -o pipefail
-            set -o xtrace
-            export PATH=$PATH:/usr/local/bin/
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o pipefail
+          set -o xtrace
+          export PATH=$PATH:/usr/local/bin/
+
+          # install python packages
+          pip install "yamllint==1.6.0"
+
+          # generate and upload lint log
+          echo "Running yaml code on $PROJECT ..."
+
+          # Ensure we start with a clean environment
+          rm -f yaml-violation.log lint.log
+
+          # Get number of yaml violations. If none, this will be an
+          # empty string: ""
+          find . \
+              -type f -name "*.yml" -print \
+              -o -name "*.yaml" -print | \
+              xargs yamllint > yaml-violation.log || true
+
+          if [ -s "yaml-violation.log" ]; then
+            SHOWN=$(cat yaml-violation.log| grep -v "^$" |wc -l)
+            echo -e "First $SHOWN shown\n---" > lint.log
+            cat yaml-violation.log >> lint.log
+            sed -r -i '4,$s/^/ /g' lint.log
+          fi
 
-            # install python packages
-            pip install "yamllint==1.6.0"
-
-            # generate and upload lint log
-            echo "Running yaml code on $PROJECT ..."
-
-            # Ensure we start with a clean environment
-            rm -f yaml-violation.log lint.log
-
-            # Get number of yaml violations. If none, this will be an
-            # empty string: ""
-            find . \
-                -type f -name "*.yml" -print \
-                -o -name "*.yaml" -print | \
-                xargs yamllint > yaml-violation.log || true
-
-            if [ -s "yaml-violation.log" ]; then
-              SHOWN=$(cat yaml-violation.log| grep -v "^$" |wc -l)
-              echo -e "First $SHOWN shown\n---" > lint.log
-              cat yaml-violation.log >> lint.log
-              sed -r -i '4,$s/^/ /g' lint.log
-            fi
+- builder:
+    name: clean-workspace
+    builders:
+      - shell: |
+          #!/bin/bash
+          set -o errexit
+          set -o nounset
+          set -o pipefail
+          sudo /bin/rm -rf "$WORKSPACE"
 
 - builder:
     name: clean-workspace-log
     builders:
-        - shell: |
-            find $WORKSPACE -type f -name '*.log' | xargs rm -f
+      - shell: |
+          find $WORKSPACE -type f -name '*.log' | xargs rm -f
 
 - publisher:
     name: archive-artifacts
     publishers:
-        - archive:
-            artifacts: '{artifacts}'
-            allow-empty: true
-            fingerprint: true
-            latest-only: true
+      - archive:
+          artifacts: '{artifacts}'
+          allow-empty: true
+          fingerprint: true
+          latest-only: true
 
 - publisher:
     name: publish-coverage
                 unhealthy: 40
                 failing: 30
 
+# The majority of the email-ext plugin options are set to the default
+# for this macro so they can be managed through Jenkins' global
+# settings.
+- publisher:
+    name: email-jenkins-admins-on-failure
+    publishers:
+      - email-ext:
+          content-type: text
+          attach-build-log: true
+          compress-log: true
+          always: false
+          failure: true
+          send-to:
+            - recipients
index 5744222..59c9461 100644 (file)
@@ -1,3 +1,4 @@
+---
 #####################################################
 # Parameters for slaves using old labels
 # This will be cleaned up once the new job structure and
 - parameter:
     name: 'apex-baremetal-master-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'apex-baremetal-master'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - lf-pod1
-            default-slaves:
-                - lf-pod1
+      - label:
+          name: SLAVE_LABEL
+          default: 'apex-baremetal-master'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - lf-pod1
+          default-slaves:
+            - lf-pod1
+
 - parameter:
     name: 'apex-baremetal-danube-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'apex-baremetal-danube'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - lf-pod1
-            default-slaves:
-                - lf-pod1
+      - label:
+          name: SLAVE_LABEL
+          default: 'apex-baremetal-danube'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - lf-pod1
+          default-slaves:
+            - lf-pod1
+
 - parameter:
     name: 'apex-virtual-master-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'apex-virtual-master'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - lf-virtual2
-                - lf-virtual3
-            default-slaves:
-                - lf-virtual2
-                - lf-virtual3
+      - label:
+          name: SLAVE_LABEL
+          default: 'apex-virtual-master'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - lf-virtual2
+            - lf-virtual3
+          default-slaves:
+            - lf-virtual2
+            - lf-virtual3
 
 - parameter:
     name: 'apex-virtual-danube-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'apex-virtual-danube'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - lf-pod3
-            default-slaves:
-                - lf-pod3
+      - label:
+          name: SLAVE_LABEL
+          default: 'apex-virtual-danube'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - lf-pod3
+          default-slaves:
+            - lf-pod3
+
 - parameter:
     name: 'lf-pod1-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - lf-pod1
-            default-slaves:
-                - lf-pod1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - lf-pod1
+          default-slaves:
+            - lf-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
+
 - parameter:
     name: 'lf-pod3-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - lf-pod3
-            default-slaves:
-                - lf-pod3
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - lf-pod3
+          default-slaves:
+            - lf-pod3
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
+
 #####################################################
 # Parameters for CI baremetal PODs
 #####################################################
 - parameter:
     name: 'apex-baremetal-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'apex-baremetal'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
+      - label:
+          name: SLAVE_LABEL
+          default: 'apex-baremetal'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
 - parameter:
     name: 'compass-baremetal-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'compass-baremetal'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'compass-baremetal'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'compass-baremetal-master-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'compass-baremetal-master'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'compass-baremetal-master'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'compass-baremetal-branch-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'compass-baremetal-branch'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'compass-baremetal-branch'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'fuel-baremetal-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'fuel-baremetal'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'fuel-baremetal'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'armband-baremetal-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'armband-baremetal'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: LAB_CONFIG_URL
-            default: ssh://jenkins-enea@gerrit.opnfv.org:29418/securedlab
-            description: 'Base URI to the configuration directory'
+      - label:
+          name: SLAVE_LABEL
+          default: 'armband-baremetal'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: LAB_CONFIG_URL
+          default: ssh://jenkins-enea@gerrit.opnfv.org:29418/securedlab
+          description: 'Base URI to the configuration directory'
+
 - parameter:
     name: 'joid-baremetal-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'joid-baremetal'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: EXTERNAL_NETWORK
-            default: ext-net
-            description: "External network floating ips"
+      - label:
+          name: SLAVE_LABEL
+          default: 'joid-baremetal'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: EXTERNAL_NETWORK
+          default: ext-net
+          description: "External network floating ips"
+
 - parameter:
     name: 'daisy-baremetal-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - zte-pod2
-            default-slaves:
-                - zte-pod2
-        - label:
-            name: SLAVE_LABEL
-            default: 'daisy-baremetal'
-        - string:
-            name: INSTALLER_IP
-            default: '10.20.11.2'
-            description: 'IP of the installer'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - zte-pod2
+          default-slaves:
+            - zte-pod2
+      - label:
+          name: SLAVE_LABEL
+          default: 'daisy-baremetal'
+      - string:
+          name: INSTALLER_IP
+          default: '10.20.7.3'
+          description: 'IP of the installer'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 #####################################################
 # Parameters for CI virtual PODs
 #####################################################
 - parameter:
     name: 'apex-virtual-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'apex-virtual'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
+      - label:
+          name: SLAVE_LABEL
+          default: 'apex-virtual'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
+
 - parameter:
     name: 'compass-virtual-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'compass-virtual'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'compass-virtual'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'compass-virtual-master-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'compass-virtual-master'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'compass-virtual-master'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'compass-virtual-branch-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'compass-virtual-branch'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'compass-virtual-branch'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'fuel-virtual-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'fuel-virtual'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'fuel-virtual'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'armband-virtual-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'armband-virtual'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: LAB_CONFIG_URL
-            default: ssh://jenkins-enea@gerrit.opnfv.org:29418/securedlab
-            description: 'Base URI to the configuration directory'
+      - label:
+          name: SLAVE_LABEL
+          default: 'armband-virtual'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: LAB_CONFIG_URL
+          default: ssh://jenkins-enea@gerrit.opnfv.org:29418/securedlab
+          description: 'Base URI to the configuration directory'
+
 - parameter:
     name: 'joid-virtual-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'joid-virtual'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'joid-virtual'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'daisy-virtual-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - zte-virtual1
-                - zte-virtual2
-            default-slaves:
-                - zte-virtual1
-        - label:
-            name: SLAVE_LABEL
-            default: 'daisy-virtual'
-        - string:
-            name: INSTALLER_IP
-            default: '10.20.11.2'
-            description: 'IP of the installer'
-        - string:
-            name: BRIDGE
-            default: 'daisy1'
-            description: 'pxe bridge for booting of Fuel master'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - zte-virtual1
+            - zte-virtual2
+          default-slaves:
+            - zte-virtual1
+      - label:
+          name: SLAVE_LABEL
+          default: 'daisy-virtual'
+      - string:
+          name: INSTALLER_IP
+          default: '10.20.11.2'
+          description: 'IP of the installer'
+      - string:
+          name: BRIDGE
+          default: 'daisy1'
+          description: 'pxe bridge for booting of Daisy master'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 #####################################################
 # Parameters for build slaves
 #####################################################
-- parameter:
-    name: 'opnfv-build-enea-defaults'
-    parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'opnfv-build-enea'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
 - parameter:
     name: 'opnfv-build-centos-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'opnfv-build-centos'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
+      - label:
+          name: SLAVE_LABEL
+          default: 'opnfv-build-centos'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: BUILD_DIRECTORY
+          default: $WORKSPACE/build_output
+          description: "Directory where the build artifact will be located upon the completion of the build."
+
 - parameter:
     name: 'opnfv-build-ubuntu-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'opnfv-build-ubuntu'
-            description: 'Slave label on Jenkins'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
+      - label:
+          name: SLAVE_LABEL
+          default: 'opnfv-build-ubuntu'
+          description: 'Slave label on Jenkins'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: BUILD_DIRECTORY
+          default: $WORKSPACE/build_output
+          description: "Directory where the build artifact will be located upon the completion of the build."
+
 - parameter:
     name: 'opnfv-build-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'opnfv-build'
-            description: 'Slave label on Jenkins'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
+      - label:
+          name: SLAVE_LABEL
+          default: 'opnfv-build'
+          description: 'Slave label on Jenkins'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: BUILD_DIRECTORY
+          default: $WORKSPACE/build_output
+          description: "Directory where the build artifact will be located upon the completion of the build."
+
 - parameter:
     name: 'huawei-build-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - huawei-build
-            default-slaves:
-                - huawei-build
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - huawei-build
+          default-slaves:
+            - huawei-build
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'opnfv-build-ubuntu-arm-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'opnfv-build-ubuntu-arm'
-            description: 'Slave label on Jenkins'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
+      - label:
+          name: SLAVE_LABEL
+          default: 'opnfv-build-ubuntu-arm'
+          description: 'Slave label on Jenkins'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: BUILD_DIRECTORY
+          default: $WORKSPACE/build_output
+          description: "Directory where the build artifact will be located upon the completion of the build."
+
 #####################################################
 # Parameters for none-CI PODs
 #####################################################
 - parameter:
     name: 'ericsson-pod1-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - ericsson-pod1
-            default-slaves:
-                - ericsson-pod1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - ericsson-pod1
+          default-slaves:
+            - ericsson-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'cengn-pod1-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - cengn-pod1
-            default-slaves:
-                - cengn-pod1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - cengn-pod1
+          default-slaves:
+            - cengn-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'intel-pod1-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - intel-pod1
-            default-slaves:
-                - intel-pod1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - intel-pod1
+          default-slaves:
+            - intel-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'intel-pod2-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - intel-pod2
-            default-slaves:
-                - intel-pod2
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - intel-pod2
+          default-slaves:
+            - intel-pod2
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
+
 - parameter:
     name: 'intel-pod9-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - intel-pod9
-            default-slaves:
-                - intel-pod9
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - intel-pod9
+          default-slaves:
+            - intel-pod9
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'intel-pod10-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - intel-pod10
-            default-slaves:
-                - intel-pod10
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - intel-pod10
+          default-slaves:
+            - intel-pod10
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'intel-pod12-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - intel-pod12
-            default-slaves:
-                - intel-pod12
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - intel-pod12
+          default-slaves:
+            - intel-pod12
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'huawei-pod3-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - huawei-pod3
-            default-slaves:
-                - huawei-pod3
-        - label:
-            name: SLAVE_LABEL
-            default: 'huawei-test'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - huawei-pod3
+          default-slaves:
+            - huawei-pod3
+      - label:
+          name: SLAVE_LABEL
+          default: 'huawei-test'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'huawei-pod4-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - huawei-pod4
-            default-slaves:
-                - huawei-pod4
-        - label:
-            name: SLAVE_LABEL
-            default: 'huawei-test'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - huawei-pod4
+          default-slaves:
+            - huawei-pod4
+      - label:
+          name: SLAVE_LABEL
+          default: 'huawei-test'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'intel-pod8-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - intel-pod8
-            default-slaves:
-                - intel-pod8
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - intel-pod8
+          default-slaves:
+            - intel-pod8
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+
+- parameter:
+    name: 'huawei-virtual5-defaults'
+    parameters:
+      - label:
+          name: SLAVE_LABEL
+          default: 'huawei-virtual5'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+
 - parameter:
     name: 'huawei-virtual7-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - huawei-virtual7
-            default-slaves:
-                - huawei-virtual7
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - huawei-virtual7
+          default-slaves:
+            - huawei-virtual7
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+
 - parameter:
     name: 'huawei-pod7-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - huawei-pod7
-            default-slaves:
-                - huawei-pod7
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - huawei-pod7
+          default-slaves:
+            - huawei-pod7
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+
 - parameter:
     name: 'zte-pod1-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - zte-pod1
-            default-slaves:
-                - zte-pod1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: INSTALLER_IP
-            default: '10.20.6.2'
-            description: 'IP of the installer'
-        - string:
-            name: BRIDGE
-            default: 'br6'
-            description: 'pxe bridge for booting of Fuel master'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - zte-pod1
+          default-slaves:
+            - zte-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: INSTALLER_IP
+          default: '10.20.6.2'
+          description: 'IP of the installer'
+      - string:
+          name: BRIDGE
+          default: 'br6'
+          description: 'pxe bridge for booting of Fuel master'
+
 - parameter:
     name: 'zte-pod2-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - zte-pod2
-            default-slaves:
-                - zte-pod2
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: INSTALLER_IP
-            default: '10.20.7.3'
-            description: 'IP of the installer'
-        - string:
-            name: BRIDGE
-            default: 'br7'
-            description: 'pxe bridge for booting of Fuel master'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - zte-pod2
+          default-slaves:
+            - zte-pod2
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: INSTALLER_IP
+          default: '10.20.7.3'
+          description: 'IP of the installer'
+      - string:
+          name: BRIDGE
+          default: 'br7'
+          description: 'pxe bridge for booting of Fuel master'
+
 - parameter:
     name: 'zte-pod3-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - zte-pod3
-            default-slaves:
-                - zte-pod3
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: BRIDGE
-            default: 'br0'
-            description: 'pxe bridge for booting of Fuel master'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - zte-pod3
+          default-slaves:
+            - zte-pod3
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: BRIDGE
+          default: 'br0'
+          description: 'pxe bridge for booting of Fuel master'
+
+- parameter:
+    name: zte-pod4-defaults
+    parameters:
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - zte-pod4
+          default-slaves:
+            - zte-pod4
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'juniper-pod1-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - juniper-pod1
-            default-slaves:
-                - juniper-pod1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: CEPH_DISKS
-            default: /srv
-            description: "Disks to use by ceph (comma separated list)"
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - juniper-pod1
+          default-slaves:
+            - juniper-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: CEPH_DISKS
+          default: /srv
+          description: "Disks to use by ceph (comma separated list)"
+
 - parameter:
     name: 'orange-pod1-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - orange-pod1
-            default-slaves:
-                - orange-pod1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - orange-pod1
+          default-slaves:
+            - orange-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'orange-pod2-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - orange-pod2
-            default-slaves:
-                - orange-pod2
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - orange-pod2
+          default-slaves:
+            - orange-pod2
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'orange-pod5-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - orange-pod5
-            default-slaves:
-                - orange-pod5
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - orange-pod5
+          default-slaves:
+            - orange-pod5
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'dell-pod1-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - dell-pod1
-            default-slaves:
-                - dell-pod1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - dell-pod1
+          default-slaves:
+            - dell-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'dell-pod2-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - dell-pod2
-            default-slaves:
-                - dell-pod2
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - dell-pod2
+          default-slaves:
+            - dell-pod2
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'nokia-pod1-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - nokia-pod1
-            default-slaves:
-                - nokia-pod1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to use for Apex'
-- parameter:
-    name: 'arm-pod2-defaults'
-    parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - arm-pod2
-            default-slaves:
-                - arm-pod2
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: LAB_CONFIG_URL
-            default: ssh://jenkins-enea@gerrit.opnfv.org:29418/securedlab
-            description: 'Base URI to the configuration directory'
-- parameter:
-    name: 'arm-pod3-defaults'
-    parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - arm-pod3
-            default-slaves:
-                - arm-pod3
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: LAB_CONFIG_URL
-            default: ssh://jenkins-enea@gerrit.opnfv.org:29418/securedlab
-            description: 'Base URI to the configuration directory'
-- parameter:
-    name: 'arm-pod4-defaults'
-    parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - arm-pod4
-            default-slaves:
-                - arm-pod4
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: LAB_CONFIG_URL
-            default: ssh://jenkins-enea@gerrit.opnfv.org:29418/securedlab
-            description: 'Base URI to the configuration directory'
-- parameter:
-    name: 'arm-virtual1-defaults'
-    parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - arm-virtual1
-            default-slaves:
-                - arm-virtual1
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: LAB_CONFIG_URL
-            default: ssh://jenkins-enea@gerrit.opnfv.org:29418/securedlab
-            description: 'Base URI to the configuration directory'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - nokia-pod1
+          default-slaves:
+            - nokia-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to use for Apex'
+
 - parameter:
     name: 'intel-virtual6-defaults'
     parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - intel-virtual6
-            default-slaves:
-                - intel-virtual6
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-- parameter:
-    name: 'ool-defaults'
-    parameters:
-        - node:
-            name: SLAVE_NAME
-            description: 'Slave name on Jenkins'
-            allowed-slaves:
-                - ool-virtual1
-                - ool-virtual2
-                - ool-virtual3
-            default-slaves:
-                - '{default-slave}'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: SSH_KEY
-            default: /root/.ssh/id_rsa
-            description: 'SSH key to be used'
-- parameter:
-    name: 'ool-virtual1-defaults'
-    parameters:
-        - 'ool-defaults':
-            default-slave: 'ool-virtual1'
-- parameter:
-    name: 'ool-virtual2-defaults'
-    parameters:
-        - 'ool-defaults':
-            default-slave: 'ool-virtual2'
-- parameter:
-    name: 'ool-virtual3-defaults'
-    parameters:
-        - 'ool-defaults':
-            default-slave: 'ool-virtual3'
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - intel-virtual6
+          default-slaves:
+            - intel-virtual6
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
+- parameter:
+    name: 'intel-virtual10-defaults'
+    parameters:
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - intel-virtual10
+          default-slaves:
+            - intel-virtual10
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
+- parameter:
+    name: 'doctor-defaults'
+    parameters:
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - '{default-slave}'
+          default-slaves:
+            - '{default-slave}'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: SSH_KEY
+          default: /root/.ssh/id_rsa
+          description: 'SSH key to be used'
+
+- parameter:
+    name: 'doctor-apex-verify-defaults'
+    parameters:
+      - 'doctor-defaults':
+          default-slave: 'doctor-apex-verify'
+
+- parameter:
+    name: 'doctor-fuel-verify-defaults'
+    parameters:
+      - 'doctor-defaults':
+          default-slave: 'doctor-fuel-verify'
+
+- parameter:
+    name: 'doctor-joid-verify-defaults'
+    parameters:
+      - 'doctor-defaults':
+          default-slave: 'doctor-joid-verify'
+
 - parameter:
     name: 'multisite-virtual-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'multisite-virtual'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'multisite-virtual'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'ericsson-virtual5-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'ericsson-virtual5'
-        - string:
-            name: GIT_BASE
-            default: https://git.opendaylight.org/gerrit/p/$PROJECT.git
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'ericsson-virtual5'
+      - string:
+          name: GIT_BASE
+          default: https://git.opendaylight.org/gerrit/p/$PROJECT.git
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'ericsson-virtual12-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'ericsson-virtual12'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'ericsson-virtual12'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'ericsson-virtual13-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'ericsson-virtual13'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'ericsson-virtual13'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
+- parameter:
+    name: 'ericsson-virtual-pod1bl01-defaults'
+    parameters:
+      - label:
+          name: SLAVE_LABEL
+          default: 'ericsson-virtual-pod1bl01'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'odl-netvirt-virtual-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'odl-netvirt-virtual'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'odl-netvirt-virtual'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 - parameter:
     name: 'odl-netvirt-virtual-intel-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'odl-netvirt-virtual-intel'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'odl-netvirt-virtual-intel'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
+- parameter:
+    name: 'flex-pod1-defaults'
+    parameters:
+      - node:
+          name: SLAVE_NAME
+          description: 'Slave name on Jenkins'
+          allowed-slaves:
+            - flex-pod1
+          default-slaves:
+            - flex-pod1
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+
 #####################################################
 # These slaves are just dummy slaves for sandbox jobs
 #####################################################
 - parameter:
     name: 'sandbox-baremetal-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'sandbox-baremetal'
-            description: 'Slave label on Jenkins'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
+      - label:
+          name: SLAVE_LABEL
+          default: 'sandbox-baremetal'
+          description: 'Slave label on Jenkins'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: BUILD_DIRECTORY
+          default: $WORKSPACE/build_output
+          description: "Directory where the build artifact will be located upon the completion of the build."
+
 - parameter:
     name: 'sandbox-virtual-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'sandbox-virtual'
-            description: 'Slave label on Jenkins'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
+      - label:
+          name: SLAVE_LABEL
+          default: 'sandbox-virtual'
+          description: 'Slave label on Jenkins'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: BUILD_DIRECTORY
+          default: $WORKSPACE/build_output
+          description: "Directory where the build artifact will be located upon the completion of the build."
+
 - parameter:
     name: 'dummy-pod1-defaults'
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'dummy-pod1'
-            description: 'Slave label on Jenkins'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: 'Git URL to use on this Jenkins Slave'
-        - string:
-            name: BUILD_DIRECTORY
-            default: $WORKSPACE/build_output
-            description: "Directory where the build artifact will be located upon the completion of the build."
+      - label:
+          name: SLAVE_LABEL
+          default: 'dummy-pod1'
+          description: 'Slave label on Jenkins'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: 'Git URL to use on this Jenkins Slave'
+      - string:
+          name: BUILD_DIRECTORY
+          default: $WORKSPACE/build_output
+          description: "Directory where the build artifact will be located upon the completion of the build."
index 13ea9b3..ac04962 100644 (file)
@@ -1,3 +1,4 @@
+---
 ########################
 # Job configuration for joid
 ########################
 
     installer: '{name}'
 
-#--------------------------------
-# BRANCH ANCHORS
-#--------------------------------
+    # -------------------------------
+    # BRANCH ANCHORS
+    # -------------------------------
     master: &master
-        stream: master
-        branch: '{stream}'
-        disabled: false
-        gs-pathname: ''
-    danube: &danube
-        stream: danube
-        branch: 'stable/{stream}'
-        disabled: false
-        gs-pathname: '/{stream}'
-#--------------------------------
-# POD, INSTALLER, AND BRANCH MAPPING
-#--------------------------------
-#        CI PODs
-#--------------------------------
+      stream: master
+      branch: '{stream}'
+      disabled: false
+      gs-pathname: ''
+    # -------------------------------
+    # POD, INSTALLER, AND BRANCH MAPPING
+    # -------------------------------
+    #        CI PODs
+    # -------------------------------
     pod:
-        - baremetal:
-            slave-label: joid-baremetal
-            <<: *master
-        - virtual:
-            slave-label: joid-virtual
-            <<: *master
-        - baremetal:
-            slave-label: joid-baremetal
-            <<: *danube
-        - virtual:
-            slave-label: joid-virtual
-            <<: *danube
-#--------------------------------
-#        None-CI PODs
-#--------------------------------
-        - orange-pod1:
-            slave-label: orange-pod1
-            <<: *master
-        - cengn-pod1:
-            slave-label: cengn-pod1
-            <<: *master
-#--------------------------------
-# scenarios
-#--------------------------------
+      - baremetal:
+          slave-label: joid-baremetal
+          <<: *master
+      - virtual:
+          slave-label: joid-virtual
+          <<: *master
+      # -------------------------------
+      #        None-CI PODs
+      # -------------------------------
+      - orange-pod1:
+          slave-label: orange-pod1
+          <<: *master
+      - cengn-pod1:
+          slave-label: cengn-pod1
+          <<: *master
+    # -------------------------------
+    # scenarios
+    # -------------------------------
     scenario:
-        - 'os-nosdn-nofeature-noha':
-            auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
-        - 'os-nosdn-nofeature-ha':
-            auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
-        - 'os-nosdn-lxd-ha':
-            auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
-        - 'os-nosdn-lxd-noha':
-            auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
-        - 'os-odl_l2-nofeature-ha':
-            auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
-        - 'os-onos-nofeature-ha':
-            auto-trigger-name: 'daily-trigger-disabled'
-        - 'os-odl_l2-nofeature-noha':
-            auto-trigger-name: 'daily-trigger-disabled'
-        - 'os-onos-nofeature-noha':
-            auto-trigger-name: 'daily-trigger-disabled'
-        - 'os-onos-sfc-ha':
-            auto-trigger-name: 'daily-trigger-disabled'
-        - 'os-ocl-nofeature-ha':
-            auto-trigger-name: 'daily-trigger-disabled'
-        - 'os-ocl-nofeature-noha':
-            auto-trigger-name: 'daily-trigger-disabled'
-        - 'k8-nosdn-nofeature-noha':
-            auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
-        - 'k8-nosdn-lb-noha':
-            auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
+      - 'os-nosdn-nofeature-noha':
+          auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
+      - 'os-nosdn-nofeature-ha':
+          auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
+      - 'os-nosdn-lxd-ha':
+          auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
+      - 'os-nosdn-lxd-noha':
+          auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
+      - 'os-odl_l2-nofeature-ha':
+          auto-trigger-name: 'daily-trigger-disabled'
+      - 'os-onos-nofeature-ha':
+          auto-trigger-name: 'daily-trigger-disabled'
+      - 'os-odl_l2-nofeature-noha':
+          auto-trigger-name: 'daily-trigger-disabled'
+      - 'os-onos-nofeature-noha':
+          auto-trigger-name: 'daily-trigger-disabled'
+      - 'os-onos-sfc-ha':
+          auto-trigger-name: 'daily-trigger-disabled'
+      - 'os-ocl-nofeature-ha':
+          auto-trigger-name: 'daily-trigger-disabled'
+      - 'os-ocl-nofeature-noha':
+          auto-trigger-name: 'daily-trigger-disabled'
+      - 'k8-nosdn-nofeature-noha':
+          auto-trigger-name: 'daily-trigger-disabled'
+      - 'k8-nosdn-lb-noha':
+          auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
+      - 'k8-ovn-lb-noha':
+          auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
+      - 'os-nosdn-openbaton-ha':
+          auto-trigger-name: 'joid-{scenario}-{pod}-{stream}-trigger'
 
     jobs:
-        - 'joid-{scenario}-{pod}-daily-{stream}'
-        - 'joid-deploy-{pod}-daily-{stream}'
+      - 'joid-{scenario}-{pod}-daily-{stream}'
+      - 'joid-deploy-{pod}-daily-{stream}'
 
 ########################
 # job templates
     concurrent: false
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 4
-            max-per-node: 1
-            option: 'project'
-        - build-blocker:
-            use-build-blocker: true
-            blocking-jobs:
-                - 'joid-os-.*?-{pod}-daily-.*'
-            block-level: 'NODE'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 4
+          max-per-node: 1
+          option: 'project'
+      - build-blocker:
+          use-build-blocker: true
+          blocking-jobs:
+            - 'joid-os-.*?-{pod}-daily-.*'
+          block-level: 'NODE'
 
     wrappers:
-        - build-name:
-            name: '$BUILD_NUMBER - Scenario: $DEPLOY_SCENARIO'
+      - build-name:
+          name: '$BUILD_NUMBER - Scenario: $DEPLOY_SCENARIO'
 
     triggers:
-        - '{auto-trigger-name}'
+      - '{auto-trigger-name}'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - '{installer}-defaults'
-        - '{slave-label}-defaults':
-            installer: '{installer}'
-        - string:
-            name: DEPLOY_SCENARIO
-            default: '{scenario}'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - '{installer}-defaults'
+      - '{slave-label}-defaults':
+          installer: '{installer}'
+      - string:
+          name: DEPLOY_SCENARIO
+          default: '{scenario}'
 
     builders:
-        - description-setter:
-            description: "POD: $NODE_NAME"
-        - trigger-builds:
-            - project: 'joid-deploy-{pod}-daily-{stream}'
-              current-parameters: true
-              predefined-parameters:
-                DEPLOY_SCENARIO={scenario}
-              same-node: true
-              block: true
-        - trigger-builds:
-            - project: 'functest-joid-{pod}-daily-{stream}'
-              current-parameters: false
-              predefined-parameters:
-                DEPLOY_SCENARIO={scenario}
-              block: true
-              same-node: true
-              block-thresholds:
-                build-step-failure-threshold: 'never'
-                failure-threshold: 'never'
-                unstable-threshold: 'FAILURE'
-        - trigger-builds:
-            - project: 'yardstick-joid-{pod}-daily-{stream}'
-              current-parameters: false
-              predefined-parameters:
-                DEPLOY_SCENARIO={scenario}
-              block: true
-              same-node: true
-              block-thresholds:
-                build-step-failure-threshold: 'never'
-                failure-threshold: 'never'
-                unstable-threshold: 'FAILURE'
-        # 1.dovetail only master by now, not sync with A/B/C branches
-        # 2.here the stream means the SUT stream, dovetail stream is defined in its own job
-        # 3.only debug testsuite here(includes basic testcase,
-        #   i.e. one tempest smoke ipv6, two vping from functest)
-        # 4.not used for release criteria or compliance,
-        #   only to debug the dovetail tool bugs with joid
-        #- trigger-builds:
-        #    - project: 'dovetail-joid-{pod}-proposed_tests-{stream}'
-        #      current-parameters: false
-        #      predefined-parameters:
-        #        DEPLOY_SCENARIO={scenario}
-        #      block: true
-        #      same-node: true
-        #      block-thresholds:
-        #        build-step-failure-threshold: 'never'
-        #        failure-threshold: 'never'
-        #        unstable-threshold: 'FAILURE'
+      - description-setter:
+          description: "POD: $NODE_NAME"
+      - trigger-builds:
+          - project: 'joid-deploy-{pod}-daily-{stream}'
+            current-parameters: true
+            predefined-parameters:
+              DEPLOY_SCENARIO={scenario}
+            same-node: true
+            block: true
+      - trigger-builds:
+          - project: 'functest-joid-{pod}-daily-{stream}'
+            current-parameters: false
+            predefined-parameters:
+              DEPLOY_SCENARIO={scenario}
+            block: true
+            same-node: true
+            block-thresholds:
+              build-step-failure-threshold: 'never'
+              failure-threshold: 'never'
+              unstable-threshold: 'FAILURE'
+      - trigger-builds:
+          - project: 'yardstick-joid-{pod}-daily-{stream}'
+            current-parameters: false
+            predefined-parameters:
+              DEPLOY_SCENARIO={scenario}
+            block: true
+            same-node: true
+            block-thresholds:
+              build-step-failure-threshold: 'never'
+              failure-threshold: 'never'
+              unstable-threshold: 'FAILURE'
+# 1.dovetail only master by now, not sync with A/B/C branches
+# 2.here the stream means the SUT stream, dovetail stream is defined in
+#   its own job
+# 3.only debug testsuite here(includes basic testcase,
+#   i.e. one tempest smoke ipv6, two vping from functest)
+# 4.not used for release criteria or compliance,
+#   only to debug the dovetail tool bugs with joid
+# - trigger-builds:
+#     - project: 'dovetail-joid-{pod}-proposed_tests-{stream}'
+#       current-parameters: false
+#       predefined-parameters:
+#         DEPLOY_SCENARIO={scenario}
+#       block: true
+#       same-node: true
+#       block-thresholds:
+#         build-step-failure-threshold: 'never'
+#         failure-threshold: 'never'
+#         unstable-threshold: 'FAILURE'
 
 - job-template:
     name: 'joid-deploy-{pod}-daily-{stream}'
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 4
-            max-per-node: 1
-            option: 'project'
-        - build-blocker:
-            use-build-blocker: true
-            blocking-jobs:
-                - 'joid-deploy-{pod}-daily-.*'
-            block-level: 'NODE'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 4
+          max-per-node: 1
+          option: 'project'
+      - build-blocker:
+          use-build-blocker: true
+          blocking-jobs:
+            - 'joid-deploy-{pod}-daily-.*'
+          block-level: 'NODE'
 
     wrappers:
-        - build-name:
-            name: '$BUILD_NUMBER - Scenario: $DEPLOY_SCENARIO'
-        - timeout:
-            timeout: 180
-            fail: true
+      - build-name:
+          name: '$BUILD_NUMBER - Scenario: $DEPLOY_SCENARIO'
+      - timeout:
+          timeout: 180
+          fail: true
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - '{installer}-defaults'
-        - '{slave-label}-defaults':
-            installer: '{installer}'
-        - string:
-            name: DEPLOY_SCENARIO
-            default: 'os-odl_l2-nofeature-ha'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - '{installer}-defaults'
+      - '{slave-label}-defaults':
+          installer: '{installer}'
+      - string:
+          name: DEPLOY_SCENARIO
+          default: 'os-odl_l2-nofeature-ha'
 
     scm:
-        - git-scm
+      - git-scm
 
     builders:
-        - description-setter:
-            description: "POD: $NODE_NAME"
-        - 'builder-macro'
+      - description-setter:
+          description: "POD: $NODE_NAME"
+      - 'builder-macro'
 ########################
 # builder macros
 ########################
 - builder:
     name: 'builder-macro'
     builders:
-        - shell: |
-            #!/bin/bash
-            echo "Running $INSTALLER_TYPE with controller $SDN_CONTROLLER"
-            echo
-            echo "------ First Executing clean.sh ------"
-            cd $WORKSPACE/ci
-            ./clean.sh
-        - shell:
-            !include-raw: ./joid-deploy.sh
+      - shell: |
+          #!/bin/bash
+          echo "Running $INSTALLER_TYPE with controller $SDN_CONTROLLER"
+          echo
+          echo "------ First Executing clean.sh ------"
+          cd $WORKSPACE/ci
+          ./clean.sh
+      - shell:
+          !include-raw: ./joid-deploy.sh
 
 ########################
 # trigger macros
 - trigger:
     name: 'joid-os-nosdn-nofeature-ha-baremetal-master-trigger'
     triggers:
-        - timed: '5 2 * * *'
+      - timed: '5 2 * * *'
 - trigger:
     name: 'joid-os-nosdn-nofeature-ha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-nosdn-nofeature-ha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-nosdn-nofeature-ha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# os-nosdn-nofeature-ha trigger - branch: danube
-- trigger:
-    name: 'joid-os-nosdn-nofeature-ha-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 2 * * *'
-- trigger:
-    name: 'joid-os-nosdn-nofeature-ha-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-nosdn-nofeature-ha-orange-pod1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-nosdn-nofeature-ha-cengn-pod1-danube-trigger'
-    triggers:
-        - timed: ''
+      - timed: ''
 # os-odl_l2-nofeature-ha trigger - branch: master
 - trigger:
     name: 'joid-os-odl_l2-nofeature-ha-baremetal-master-trigger'
     triggers:
-        - timed: '5 7 * * *'
+      - timed: '5 7 * * *'
 - trigger:
     name: 'joid-os-odl_l2-nofeature-ha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-odl_l2-nofeature-ha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-odl_l2-nofeature-ha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# os-odl_l2-nofeature-ha trigger - branch: danube
-- trigger:
-    name: 'joid-os-odl_l2-nofeature-ha-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 7 * * *'
-- trigger:
-    name: 'joid-os-odl_l2-nofeature-ha-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-odl_l2-nofeature-ha-orange-pod1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-odl_l2-nofeature-ha-cengn-pod1-danube-trigger'
-    triggers:
-        - timed: ''
+      - timed: ''
 # os-onos-nofeature-ha trigger - branch: master
 - trigger:
     name: 'joid-os-onos-nofeature-ha-baremetal-master-trigger'
     triggers:
-        - timed: '5 12 * * *'
+      - timed: '5 12 * * *'
 - trigger:
     name: 'joid-os-onos-nofeature-ha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-onos-nofeature-ha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-onos-nofeature-ha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# os-onos-nofeature-ha trigger - branch: danube
-- trigger:
-    name: 'joid-os-onos-nofeature-ha-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 12 * * *'
-- trigger:
-    name: 'joid-os-onos-nofeature-ha-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-onos-nofeature-ha-orange-pod1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-onos-nofeature-ha-cengn-pod1-danube-trigger'
-    triggers:
-        - timed: ''
+      - timed: ''
 # os-onos-sfc-ha trigger - branch: master
 - trigger:
     name: 'joid-os-onos-sfc-ha-baremetal-master-trigger'
     triggers:
-        - timed: '5 17 * * *'
+      - timed: '5 17 * * *'
 - trigger:
     name: 'joid-os-onos-sfc-ha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-onos-sfc-ha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-onos-sfc-ha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# os-onos-sfc-ha trigger - branch: danube
-- trigger:
-    name: 'joid-os-onos-sfc-ha-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 17 * * *'
-- trigger:
-    name: 'joid-os-onos-sfc-ha-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-onos-sfc-ha-orange-pod1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-onos-sfc-ha-cengn-pod1-danube-trigger'
-    triggers:
-        - timed: ''
+      - timed: ''
 # os-nosdn-lxd-noha trigger - branch: master
 - trigger:
     name: 'joid-os-nosdn-lxd-noha-baremetal-master-trigger'
     triggers:
-        - timed: '5 22 * * *'
+      - timed: '5 22 * * *'
 - trigger:
     name: 'joid-os-nosdn-lxd-noha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-nosdn-lxd-noha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-nosdn-lxd-noha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# os-nosdn-lxd-noha trigger - branch: danube
-- trigger:
-    name: 'joid-os-nosdn-lxd-noha-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 22 * * *'
-- trigger:
-    name: 'joid-os-nosdn-lxd-noha-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-nosdn-lxd-noha-orange-pod1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-nosdn-lxd-noha-cengn-pod1-danube-trigger'
-    triggers:
-        - timed: ''
+      - timed: ''
 # os-nosdn-lxd-ha trigger - branch: master
 - trigger:
     name: 'joid-os-nosdn-lxd-ha-baremetal-master-trigger'
     triggers:
-        - timed: '5 10 * * *'
+      - timed: '5 10 * * *'
 - trigger:
     name: 'joid-os-nosdn-lxd-ha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-nosdn-lxd-ha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-nosdn-lxd-ha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# os-nosdn-lxd-ha trigger - branch: danube
-- trigger:
-    name: 'joid-os-nosdn-lxd-ha-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 10 * * *'
-- trigger:
-    name: 'joid-os-nosdn-lxd-ha-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-nosdn-lxd-ha-orange-pod1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-nosdn-lxd-ha-cengn-pod1-danube-trigger'
-    triggers:
-        - timed: ''
+      - timed: ''
 # os-nosdn-nofeature-noha trigger - branch: master
 - trigger:
     name: 'joid-os-nosdn-nofeature-noha-baremetal-master-trigger'
     triggers:
-        - timed: '5 4 * * *'
+      - timed: '5 4 * * *'
 - trigger:
     name: 'joid-os-nosdn-nofeature-noha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-nosdn-nofeature-noha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-os-nosdn-nofeature-noha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# os-nosdn-nofeature-noha trigger - branch: danube
-- trigger:
-    name: 'joid-os-nosdn-nofeature-noha-baremetal-danube-trigger'
-    triggers:
-        - timed: '0 4 * * *'
-- trigger:
-    name: 'joid-os-nosdn-nofeature-noha-virtual-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-nosdn-nofeature-noha-orange-pod1-danube-trigger'
-    triggers:
-        - timed: ''
-- trigger:
-    name: 'joid-os-nosdn-nofeature-noha-cengn-pod1-danube-trigger'
-    triggers:
-        - timed: ''
+      - timed: ''
 # k8-nosdn-nofeature-noha trigger - branch: master
 - trigger:
     name: 'joid-k8-nosdn-nofeature-noha-baremetal-master-trigger'
     triggers:
-        - timed: '5 15 * * *'
+      - timed: '5 15 * * *'
 - trigger:
     name: 'joid-k8-nosdn-nofeature-noha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-k8-nosdn-nofeature-noha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
     name: 'joid-k8-nosdn-nofeature-noha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# k8-nosdn-nofeature-noha trigger - branch: danube
+      - timed: ''
+# k8-nosdn-lb-noha trigger - branch: master
 - trigger:
-    name: 'joid-k8-nosdn-nofeature-noha-baremetal-danube-trigger'
+    name: 'joid-k8-nosdn-lb-noha-baremetal-master-trigger'
     triggers:
-        - timed: '0 15 * * *'
+      - timed: '5 20 * * *'
 - trigger:
-    name: 'joid-k8-nosdn-nofeature-noha-virtual-danube-trigger'
+    name: 'joid-k8-nosdn-lb-noha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
-    name: 'joid-k8-nosdn-nofeature-noha-orange-pod1-danube-trigger'
+    name: 'joid-k8-nosdn-lb-noha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
-    name: 'joid-k8-nosdn-nofeature-noha-cengn-pod1-danube-trigger'
+    name: 'joid-k8-nosdn-lb-noha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# k8-nosdn-lb-noha trigger - branch: master
+      - timed: ''
+# k8-ovn-lb-noha trigger - branch: master
 - trigger:
-    name: 'joid-k8-nosdn-lb-noha-baremetal-master-trigger'
+    name: 'joid-k8-ovn-lb-noha-baremetal-master-trigger'
     triggers:
-        - timed: '5 20 * * *'
+      - timed: '5 17 * * *'
 - trigger:
-    name: 'joid-k8-nosdn-lb-noha-virtual-master-trigger'
+    name: 'joid-k8-ovn-lb-noha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
-    name: 'joid-k8-nosdn-lb-noha-orange-pod1-master-trigger'
+    name: 'joid-k8-ovn-lb-noha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
-    name: 'joid-k8-nosdn-lb-noha-cengn-pod1-master-trigger'
+    name: 'joid-k8-ovn-lb-noha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
-# k8-nosdn-lb-noha trigger - branch: danube
+      - timed: ''
+
+# os-nosdn-openbaton-ha trigger - branch: master
 - trigger:
-    name: 'joid-k8-nosdn-lb-noha-baremetal-danube-trigger'
+    name: 'joid-os-nosdn-openbaton-ha-baremetal-master-trigger'
     triggers:
-        - timed: '0 20 * * *'
+      - timed: '5 25 * * *'
 - trigger:
-    name: 'joid-k8-nosdn-lb-noha-virtual-danube-trigger'
+    name: 'joid-os-nosdn-openbaton-ha-virtual-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
-    name: 'joid-k8-nosdn-lb-noha-orange-pod1-danube-trigger'
+    name: 'joid-os-nosdn-openbaton-ha-orange-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
 - trigger:
-    name: 'joid-k8-nosdn-lb-noha-cengn-pod1-danube-trigger'
+    name: 'joid-os-nosdn-openbaton-ha-cengn-pod1-master-trigger'
     triggers:
-        - timed: ''
+      - timed: ''
index e197dbd..9740d38 100644 (file)
@@ -94,9 +94,6 @@ EXTRA=${DEPLOY_OPTIONS[4]}
 if [ "$SDN_CONTROLLER" == 'odl_l2' ] || [ "$SDN_CONTROLLER" == 'odl_l3' ]; then
     SDN_CONTROLLER='odl'
 fi
-if [ "$HA_MODE" == 'noha' ]; then
-    HA_MODE='nonha'
-fi
 
 # Add extra to features
 if [ "$EXTRA" != "" ];then
index 03fab55..3b30cb6 100644 (file)
@@ -1,37 +1,38 @@
+---
 - project:
     name: 'joid-verify-jobs'
 
     project: 'joid'
 
     installer: 'joid'
-#####################################
-# branch definitions
-#####################################
+    #####################################
+    # branch definitions
+    #####################################
     stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
-            disabled: false
-        - danube:
-            branch: 'stable/{stream}'
-            gs-pathname: '/{stream}'
-            disabled: false
-#####################################
-# patch verification phases
-#####################################
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
+      - danube:
+          branch: 'stable/{stream}'
+          gs-pathname: '/{stream}'
+          disabled: false
+    #####################################
+    # patch verification phases
+    #####################################
     phase:
-        - 'basic':
-            slave-label: 'opnfv-build-ubuntu'
-        - 'deploy-virtual':
-            slave-label: 'joid-virtual'
-        - 'smoke-test':
-            slave-label: 'joid-virtual'
-#####################################
-# jobs
-#####################################
+      - 'basic':
+          slave-label: 'opnfv-build-ubuntu'
+      - 'deploy-virtual':
+          slave-label: 'joid-virtual'
+      - 'smoke-test':
+          slave-label: 'joid-virtual'
+    #####################################
+    # jobs
+    #####################################
     jobs:
-        - 'joid-verify-{stream}'
-        - 'joid-verify-{phase}-{stream}'
+      - 'joid-verify-{stream}'
+      - 'joid-verify-{phase}-{stream}'
 #####################################
 # job templates
 #####################################
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 4
-            max-per-node: 1
-            option: 'project'
-        - build-blocker:
-            use-build-blocker: true
-            blocking-jobs:
-                - 'joid-verify-master'
-                - 'joid-verify-danube'
-            block-level: 'NODE'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 4
+          max-per-node: 1
+          option: 'project'
+      - build-blocker:
+          use-build-blocker: true
+          blocking-jobs:
+            - 'joid-verify-master'
+            - 'joid-verify-danube'
+          block-level: 'NODE'
 
     scm:
-        - git-scm-gerrit
+      - git-scm-gerrit
 
     wrappers:
-        - ssh-agent-wrapper
-        - timeout:
-            timeout: 360
-            fail: true
+      - ssh-agent-wrapper
+      - timeout:
+          timeout: 360
+          fail: true
 
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - patchset-created-event:
-                    exclude-drafts: 'false'
-                    exclude-trivial-rebase: 'false'
-                    exclude-no-code-change: 'false'
-                - draft-published-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'recheck'
-                - comment-added-contains-event:
-                    comment-contains-value: 'reverify'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-                disable-strict-forbidden-file-verification: 'true'
-                forbidden-file-paths:
-                  - compare-type: ANT
-                    pattern: 'docs/**|.gitignore'
-            readable-message: true
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: 'recheck'
+            - comment-added-contains-event:
+                comment-contains-value: 'reverify'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              disable-strict-forbidden-file-verification: 'true'
+              forbidden-file-paths:
+                - compare-type: ANT
+                  pattern: 'docs/**|.gitignore'
+          readable-message: true
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'joid-virtual-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'joid-virtual-defaults'
 
     builders:
-        - description-setter:
-            description: "Built on $NODE_NAME"
-        - multijob:
-            name: basic
-            condition: SUCCESSFUL
-            projects:
-                - name: 'joid-verify-basic-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    BRANCH=$BRANCH
-                    GERRIT_REFSPEC=$GERRIT_REFSPEC
-                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
-                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-        - multijob:
-            name: deploy-virtual
-            condition: SUCCESSFUL
-            projects:
-                - name: 'joid-verify-deploy-virtual-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    BRANCH=$BRANCH
-                    GERRIT_REFSPEC=$GERRIT_REFSPEC
-                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
-                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
-                  node-parameters: true
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-        - multijob:
-            name: smoke-test
-            condition: SUCCESSFUL
-            projects:
-                - name: 'joid-verify-smoke-test-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    BRANCH=$BRANCH
-                    GERRIT_REFSPEC=$GERRIT_REFSPEC
-                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
-                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
-                  node-parameters: true
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
+      - description-setter:
+          description: "Built on $NODE_NAME"
+      - multijob:
+          name: basic
+          condition: SUCCESSFUL
+          projects:
+            - name: 'joid-verify-basic-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                BRANCH=$BRANCH
+                GERRIT_REFSPEC=$GERRIT_REFSPEC
+                GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
+              kill-phase-on: FAILURE
+              abort-all-job: true
+      - multijob:
+          name: deploy-virtual
+          condition: SUCCESSFUL
+          projects:
+            - name: 'joid-verify-deploy-virtual-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                BRANCH=$BRANCH
+                GERRIT_REFSPEC=$GERRIT_REFSPEC
+                GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: true
+      - multijob:
+          name: smoke-test
+          condition: SUCCESSFUL
+          projects:
+            - name: 'joid-verify-smoke-test-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                BRANCH=$BRANCH
+                GERRIT_REFSPEC=$GERRIT_REFSPEC
+                GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: true
 
 - job-template:
     name: 'joid-verify-{phase}-{stream}'
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 4
-            max-per-node: 1
-            option: 'project'
-        - build-blocker:
-            use-build-blocker: true
-            blocking-jobs:
-                - 'joid-verify-deploy-.*'
-                - 'joid-verify-test-.*'
-            block-level: 'NODE'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 4
+          max-per-node: 1
+          option: 'project'
+      - build-blocker:
+          use-build-blocker: true
+          blocking-jobs:
+            - 'joid-verify-deploy-.*'
+            - 'joid-verify-test-.*'
+          block-level: 'NODE'
 
     scm:
-        - git-scm-gerrit
+      - git-scm-gerrit
 
     wrappers:
-        - ssh-agent-wrapper
-        - timeout:
-            timeout: 360
-            fail: true
+      - ssh-agent-wrapper
+      - timeout:
+          timeout: 360
+          fail: true
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - '{installer}-defaults'
-        - '{slave-label}-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - '{installer}-defaults'
+      - '{slave-label}-defaults'
 
     builders:
-        - description-setter:
-            description: "Built on $NODE_NAME"
-        - '{project}-verify-{phase}-macro'
+      - description-setter:
+          description: "Built on $NODE_NAME"
+      - '{project}-verify-{phase}-macro'
 #####################################
 # builder macros
 #####################################
 - builder:
     name: 'joid-verify-basic-macro'
     builders:
-        - shell: |
-            #!/bin/bash
+      - shell: |
+          #!/bin/bash
 
-            echo "Not activated!"
+          echo "Not activated!"
 
 - builder:
     name: 'joid-verify-deploy-virtual-macro'
     builders:
-        - shell: |
-            #!/bin/bash
+      - shell: |
+          #!/bin/bash
 
-            echo "Not activated!"
+          echo "Not activated!"
 
 - builder:
     name: 'joid-verify-smoke-test-macro'
     builders:
-        - shell: |
-            #!/bin/bash
+      - shell: |
+          #!/bin/bash
 
-            echo "Not activated!"
+          echo "Not activated!"
index e5b56bf..a39249a 100644 (file)
@@ -26,6 +26,7 @@
     testname:
         - 'cyclictest'
         - 'packet_forward'
+        - 'livemigration'
 #####################################
 # patch verification phases
 #####################################
                   git-revision: true
                   kill-phase-on: FAILURE
                   abort-all-job: true
+        - multijob:
+            name: livemigration-test
+            condition: SUCCESSFUL
+            projects:
+                - name: 'kvmfornfv-livemigration-daily-test-{stream}'
+                  current-parameters: false
+                  node-parameters: false
+                  git-revision: true
+                  kill-phase-on: FAILURE
+                  abort-all-job: true
+
 
 - job-template:
     name: 'kvmfornfv-daily-build-{stream}'
             !include-raw: ./kvmfornfv-download-artifact.sh
         - shell:
             !include-raw: ./kvmfornfv-test.sh
+- builder:
+    name: 'kvmfornfv-livemigration-daily-test-macro'
+    builders:
+        - shell:
+            !include-raw: ./kvmfornfv-download-artifact.sh
+        - shell:
+            !include-raw: ./kvmfornfv-test.sh
+
 #####################################
 # parameter macros
 #####################################
diff --git a/jjb/multisite/fuel-deploy-for-multisite.sh b/jjb/multisite/fuel-deploy-for-multisite.sh
deleted file mode 100755 (executable)
index 71c6cc1..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o nounset
-set -o pipefail
-
-# do not continue with the deployment if FRESH_INSTALL is not requested
-if [[ "$FRESH_INSTALL" == "true" ]]; then
-    echo "Fresh install requested. Proceeding with the installation."
-else
-    echo "Fresh install is not requested. Skipping the installation."
-    exit 0
-fi
-
-export TERM="vt220"
-export BRANCH=$(echo $BRANCH | sed 's/stable\///g')
-# get the latest successful job console log and extract the properties filename
-FUEL_DEPLOY_BUILD_URL="https://build.opnfv.org/ci/job/fuel-deploy-virtual-daily-$BRANCH/lastSuccessfulBuild/consoleText"
-FUEL_PROPERTIES_FILE=$(curl -s -L ${FUEL_DEPLOY_BUILD_URL} | grep 'ISO:' | awk '{print $2}' | sed 's/iso/properties/g')
-if [[ -z "FUEL_PROPERTIES_FILE" ]]; then
-    echo "Unable to extract the url to Fuel ISO properties from ${FUEL_DEPLOY_URL}"
-    exit 1
-fi
-
-# use known/working version of fuel
-#FUEL_PROPERTIES_FILE="opnfv-2017-03-06_16-00-15.properties"
-curl -L -s -o $WORKSPACE/latest.properties $GS_PATH/$FUEL_PROPERTIES_FILE
-
-# source the file so we get OPNFV vars
-source latest.properties
-
-# echo the info about artifact that is used during the deployment
-echo "Using ${OPNFV_ARTIFACT_URL/*\/} for deployment"
-
-# download the iso
-echo "Downloading the ISO using the link http://$OPNFV_ARTIFACT_URL"
-curl -L -s -o $WORKSPACE/opnfv.iso http://$OPNFV_ARTIFACT_URL > gsutil.iso.log 2>&1
-
-
-# set deployment parameters
-DEPLOY_SCENARIO="os-nosdn-nofeature-noha"
-export TMPDIR=$HOME/tmpdir
-BRIDGE=${BRIDGE:-pxebr}
-LAB_NAME=${NODE_NAME/-*}
-POD_NAME=${NODE_NAME/*-}
-
-if [[ "$NODE_NAME" =~ "virtual" ]]; then
-    POD_NAME="virtual_kvm"
-fi
-
-# we currently support ericsson, intel, lf and zte labs
-if [[ ! "$LAB_NAME" =~ (ericsson|intel|lf|zte) ]]; then
-    echo "Unsupported/unidentified lab $LAB_NAME. Cannot continue!"
-    exit 1
-else
-    echo "Using configuration for $LAB_NAME"
-fi
-
-# create TMPDIR if it doesn't exist
-export TMPDIR=$HOME/tmpdir
-mkdir -p $TMPDIR
-
-# change permissions down to TMPDIR
-chmod a+x $HOME
-chmod a+x $TMPDIR
-
-# clone fuel repo and checkout the sha1 that corresponds to the ISO
-echo "Cloning fuel repo"
-git clone https://gerrit.opnfv.org/gerrit/p/fuel.git fuel
-cd $WORKSPACE/fuel
-echo "Checking out $OPNFV_GIT_SHA1"
-git checkout $OPNFV_GIT_SHA1 --quiet
-
-# clone the securedlab repo
-cd $WORKSPACE
-echo "Cloning securedlab repo ${GIT_BRANCH##origin/}"
-git clone ssh://jenkins-ericsson@gerrit.opnfv.org:29418/securedlab --quiet \
-    --branch ${GIT_BRANCH##origin/}
-
-# log file name
-FUEL_LOG_FILENAME="${JOB_NAME}_${BUILD_NUMBER}.log.tar.gz"
-
-# construct the command
-DEPLOY_COMMAND="sudo $WORKSPACE/fuel/ci/deploy.sh -b file://$WORKSPACE/securedlab \
-    -l $LAB_NAME -p $POD_NAME -s $DEPLOY_SCENARIO -i file://$WORKSPACE/opnfv.iso \
-    -H -B $BRIDGE -S $TMPDIR -L $WORKSPACE/$FUEL_LOG_FILENAME"
-
-# log info to console
-echo "Deployment parameters"
-echo "--------------------------------------------------------"
-echo "Scenario: $DEPLOY_SCENARIO"
-echo "Lab: $LAB_NAME"
-echo "POD: $POD_NAME"
-echo "ISO: ${OPNFV_ARTIFACT_URL/*\/}"
-echo
-echo "Starting the deployment using $INSTALLER_TYPE. This could take some time..."
-echo "--------------------------------------------------------"
-echo
-
-# start the deployment
-echo "Issuing command"
-echo "$DEPLOY_COMMAND"
-echo
-
-$DEPLOY_COMMAND
-exit_code=$?
-
-echo
-echo "--------------------------------------------------------"
-echo "Deployment is done!"
-
-if [[ $exit_code -ne 0 ]]; then
-    echo "Deployment failed!"
-    exit $exit_code
-else
-    echo "Deployment is successful!"
-    exit 0
-fi
diff --git a/jjb/multisite/multisite-daily-jobs.yml b/jjb/multisite/multisite-daily-jobs.yml
deleted file mode 100644 (file)
index 06cefb6..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-- project:
-    name: kingbird
-
-    project: 'multisite'
-
-    jobs:
-        - 'multisite-kingbird-virtual-daily-{stream}'
-        - 'multisite-{phase}-{stream}'
-
-    phase:
-        - 'fuel-deploy-regionone-virtual':
-            slave-label: ericsson-virtual12
-        - 'fuel-deploy-regiontwo-virtual':
-            slave-label: ericsson-virtual13
-        - 'register-endpoints':
-            slave-label: ericsson-virtual12
-        - 'update-auth':
-            slave-label: ericsson-virtual13
-        - 'kingbird-deploy-virtual':
-            slave-label: ericsson-virtual12
-
-    stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
-            disabled: false
-            timed: '0 12 * * *'
-        - danube:
-            branch: 'stable/{stream}'
-            gs-pathname: '/{stream}'
-            disabled: false
-            timed: '0 0 * * *'
-
-- job-template:
-    name: 'multisite-kingbird-virtual-daily-{stream}'
-
-    project-type: multijob
-
-    disabled: '{obj:disabled}'
-
-    concurrent: false
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - choice:
-            name: FRESH_INSTALL
-            choices:
-                - 'true'
-                - 'false'
-        - string:
-            name: KINGBIRD_LOG_FILE
-            default: $WORKSPACE/kingbird.log
-        - 'opnfv-build-defaults'
-
-    triggers:
-         - timed: '{timed}'
-
-    builders:
-        - description-setter:
-            description: "Built on $NODE_NAME"
-        - multijob:
-            name: fuel-deploy-virtual
-            condition: SUCCESSFUL
-            projects:
-                - name: 'multisite-fuel-deploy-regionone-virtual-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    FUEL_VERSION=latest
-                    DEPLOY_SCENARIO=os-nosdn-nofeature-noha
-                    OS_REGION=RegionOne
-                    REGIONONE_IP=100.64.209.10
-                    REGIONTWO_IP=100.64.209.11
-                    FRESH_INSTALL=$FRESH_INSTALL
-                  node-parameters: false
-                  node-label-name: SLAVE_LABEL
-                  node-label: ericsson-virtual12
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-                - name: 'multisite-fuel-deploy-regiontwo-virtual-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    FUEL_VERSION=latest
-                    DEPLOY_SCENARIO=os-nosdn-nofeature-noha
-                    OS_REGION=RegionTwo
-                    REGIONONE_IP=100.64.209.10
-                    REGIONTWO_IP=100.64.209.11
-                    FRESH_INSTALL=$FRESH_INSTALL
-                  node-parameters: false
-                  node-label-name: SLAVE_LABEL
-                  node-label: ericsson-virtual13
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-        - multijob:
-            name: centralize-keystone
-            condition: SUCCESSFUL
-            projects:
-                - name: 'multisite-register-endpoints-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    OS_REGION=RegionOne
-                    REGIONONE_IP=100.64.209.10
-                    REGIONTWO_IP=100.64.209.11
-                    FRESH_INSTALL=$FRESH_INSTALL
-                  node-parameters: false
-                  node-label-name: SLAVE_LABEL
-                  node-label: ericsson-virtual12
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-                - name: 'multisite-update-auth-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    OS_REGION=RegionTwo
-                    REGIONONE_IP=100.64.209.10
-                    REGIONTWO_IP=100.64.209.11
-                    FRESH_INSTALL=$FRESH_INSTALL
-                  node-parameters: false
-                  node-label-name: SLAVE_LABEL
-                  node-label: ericsson-virtual13
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-        - multijob:
-            name: kingbird-deploy-virtual
-            condition: SUCCESSFUL
-            projects:
-                - name: 'multisite-kingbird-deploy-virtual-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    OS_REGION=RegionOne
-                    REGIONONE_IP=100.64.209.10
-                    REGIONTWO_IP=100.64.209.11
-                    FRESH_INSTALL=$FRESH_INSTALL
-                  node-parameters: false
-                  node-label-name: SLAVE_LABEL
-                  node-label: ericsson-virtual12
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-        - multijob:
-            name: kingbird-functest
-            condition: SUCCESSFUL
-            projects:
-                - name: 'functest-fuel-virtual-suite-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-multisite-noha
-                    FUNCTEST_SUITE_NAME=multisite
-                    OS_REGION=RegionOne
-                    REGIONONE_IP=100.64.209.10
-                    REGIONTWO_IP=100.64.209.11
-                    FRESH_INSTALL=$FRESH_INSTALL
-                  node-parameters: false
-                  node-label-name: SLAVE_LABEL
-                  node-label: ericsson-virtual12
-                  kill-phase-on: NEVER
-                  abort-all-job: false
-
-- job-template:
-    name: 'multisite-{phase}-{stream}'
-
-    concurrent: false
-
-    disabled: '{obj:disabled}'
-
-    concurrent: false
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - string:
-            name: KINGBIRD_LOG_FILE
-            default: $WORKSPACE/kingbird.log
-        - string:
-            name: GS_PATH
-            default: 'http://artifacts.opnfv.org/fuel{gs-pathname}'
-        - 'fuel-defaults'
-        - '{slave-label}-defaults'
-        - choice:
-            name: FRESH_INSTALL
-            choices:
-                - 'true'
-                - 'false'
-
-    scm:
-        - git-scm
-
-    builders:
-        - description-setter:
-            description: "Built on $NODE_NAME"
-        - 'multisite-{phase}-builder':
-            stream: '{stream}'
-
-    publishers:
-        - 'multisite-{phase}-publisher'
-
-########################
-# builder macros
-########################
-- builder:
-    name: 'multisite-fuel-deploy-regionone-virtual-builder'
-    builders:
-        - shell:
-            !include-raw-escape: ./fuel-deploy-for-multisite.sh
-        - shell: |
-            #!/bin/bash
-
-            echo "This is where we deploy fuel, extract passwords and save into file"
-
-            cd $WORKSPACE/tools/keystone/
-            ./run.sh -t controller -r fetchpass.sh -o servicepass.ini
-
-- builder:
-    name: 'multisite-fuel-deploy-regiontwo-virtual-builder'
-    builders:
-        - shell:
-            !include-raw-escape: ./fuel-deploy-for-multisite.sh
-        - shell: |
-            #!/bin/bash
-
-            echo "This is where we deploy fuel, extract publicUrl, privateUrl, and adminUrl and save into file"
-
-            cd $WORKSPACE/tools/keystone/
-            ./run.sh -t controller -r endpoint.sh -o endpoints.ini
-- builder:
-    name: 'multisite-register-endpoints-builder'
-    builders:
-        - copyartifact:
-            project: 'multisite-fuel-deploy-regiontwo-virtual-{stream}'
-            which-build: multijob-build
-            filter: "endpoints.ini"
-        - shell: |
-            #!/bin/bash
-
-            echo "This is where we register RegionTwo in RegionOne keystone using endpoints.ini"
-
-            cd $WORKSPACE/tools/keystone/
-            ./run.sh -t controller -r region.sh -d $WORKSPACE/endpoints.ini
-- builder:
-    name: 'multisite-update-auth-builder'
-    builders:
-        - copyartifact:
-            project: 'multisite-fuel-deploy-regionone-virtual-{stream}'
-            which-build: multijob-build
-            filter: "servicepass.ini"
-        - shell: |
-            #!/bin/bash
-
-            echo "This is where we read passwords from servicepass.ini and replace passwords in RegionTwo"
-
-            cd $WORKSPACE/tools/keystone/
-            ./run.sh -t controller -r writepass.sh -d $WORKSPACE/servicepass.ini
-            ./run.sh -t compute -r writepass.sh -d $WORKSPACE/servicepass.ini
-- builder:
-    name: 'multisite-kingbird-deploy-virtual-builder'
-    builders:
-        - shell: |
-            #!/bin/bash
-
-            echo "This is where we install kingbird"
-            cd $WORKSPACE/tools/kingbird
-            ./deploy.sh
-########################
-# publisher macros
-########################
-- publisher:
-    name: 'multisite-fuel-deploy-regionone-virtual-publisher'
-    publishers:
-        - archive:
-            artifacts: 'servicepass.ini'
-            allow-empty: false
-            only-if-success: true
-            fingerprint: true
-- publisher:
-    name: 'multisite-fuel-deploy-regiontwo-virtual-publisher'
-    publishers:
-        - archive:
-            artifacts: 'endpoints.ini'
-            allow-empty: false
-            only-if-success: true
-            fingerprint: true
-- publisher:
-    name: 'multisite-register-endpoints-publisher'
-    publishers:
-        - archive:
-            artifacts: 'dummy.txt'
-            allow-empty: true
-- publisher:
-    name: 'multisite-update-auth-publisher'
-    publishers:
-        - archive:
-            artifacts: 'dummy.txt'
-            allow-empty: true
-- publisher:
-    name: 'multisite-kingbird-deploy-virtual-publisher'
-    publishers:
-        - archive:
-            artifacts: 'dummy.txt'
-            allow-empty: true
-- publisher:
-    name: 'multisite-kingbird-functest-publisher'
-    publishers:
-        - archive:
-            artifacts: 'dummy.txt'
-            allow-empty: true
diff --git a/jjb/nfvbench/nfvbench.yml b/jjb/nfvbench/nfvbench.yml
new file mode 100644 (file)
index 0000000..62776d5
--- /dev/null
@@ -0,0 +1,93 @@
+---
+- project:
+    name: nfvbench
+
+    project: '{name}'
+
+    jobs:
+      - 'nfvbench-build-{stream}'
+      - 'nfvbench-verify-{stream}'
+
+    stream:
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
+          docker-tag: 'latest'
+
+- job-template:
+    name: 'nfvbench-build-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    parameters:
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      # yamllint disable rule:line-length
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: "Used for overriding the GIT URL coming from Global Jenkins configuration in case if the stuff is done on none-LF HW."
+      # yamllint enable rule:line-length
+      - 'opnfv-build-ubuntu-defaults'
+
+    scm:
+      - git-scm-gerrit
+
+    triggers:
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - comment-added-contains-event:
+                comment-contains-value: 'buildvm'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+
+    builders:
+      - shell: |
+          cd $WORKSPACE/nfvbenchvm/dib
+          bash build-image.sh
+
+- job-template:
+    name: 'nfvbench-verify-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    parameters:
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      # yamllint disable rule:line-length
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/$PROJECT
+          description: "Used for overriding the GIT URL coming from Global Jenkins configuration in case if the stuff is done on none-LF HW."
+      # yamllint enable rule:line-length
+      - 'opnfv-build-ubuntu-defaults'
+
+    scm:
+      - git-scm-gerrit
+
+    triggers:
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+
+    builders:
+      - shell: |
+          echo "pass"
index 596d377..d0dd052 100644 (file)
@@ -1,31 +1,32 @@
+---
 - project:
     name: 'opera-daily-jobs'
 
     project: 'opera'
 
-#####################################
-# branch definitions
-#####################################
+    #####################################
+    # branch definitions
+    #####################################
     master: &master
-        stream: master
-        branch: '{stream}'
-        gs-pathname: ''
-        disabled: false
+      stream: master
+      branch: '{stream}'
+      gs-pathname: ''
+      disabled: false
 
-#####################################
-# pod definitions
-#####################################
+    #####################################
+    # pod definitions
+    #####################################
     pod:
-        - virtual:
-            slave-label: 'huawei-virtual7'
-            os-version: 'xenial'
-            <<: *master
+      - virtual:
+          slave-label: 'huawei-virtual7'
+          os-version: 'xenial'
+          <<: *master
 
-#####################################
-# jobs
-#####################################
+    #####################################
+    # jobs
+    #####################################
     jobs:
-        - 'opera-{pod}-daily-{stream}'
+      - 'opera-{pod}-daily-{stream}'
 
 #####################################
 # job templates
     concurrent: false
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 1
-            max-per-node: 1
-            option: 'project'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 1
+          max-per-node: 1
+          option: 'project'
 
     scm:
-        - git-scm
+      - git-scm
 
     wrappers:
-        - ssh-agent-wrapper
-
-        - timeout:
-            timeout: 240
-            fail: true
+      - ssh-agent-wrapper
+      - timeout:
+          timeout: 240
+          fail: true
 
     triggers:
-         - timed: '@midnight'
+      - timed: '@midnight'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - string:
-            name: DEPLOY_SCENARIO
-            default: os-nosdn-openo-ha
-        - '{slave-label}-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - string:
+          name: DEPLOY_SCENARIO
+          default: os-nosdn-openo-ha
+      - '{slave-label}-defaults'
 
     builders:
-        - description-setter:
-            description: "Built on $NODE_NAME"
-        - multijob:
-            name: deploy
-            condition: SUCCESSFUL
-            projects:
-                - name: 'compass-deploy-{pod}-daily-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-openo-ha
-                    COMPASS_OS_VERSION=xenial
-                  node-parameters: true
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-        - multijob:
-            name: functest
-            condition: SUCCESSFUL
-            projects:
-                - name: 'functest-compass-{pod}-suite-{stream}'
-                  current-parameters: false
-                  predefined-parameters: |
-                    DEPLOY_SCENARIO=os-nosdn-openo-ha
-                    FUNCTEST_SUITE_NAME=opera_vims
-                  node-parameters: true
-                  kill-phase-on: NEVER
-                  abort-all-job: true
+      - description-setter:
+          description: "Built on $NODE_NAME"
+      - multijob:
+          name: deploy
+          condition: SUCCESSFUL
+          projects:
+            - name: 'compass-deploy-{pod}-daily-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                DEPLOY_SCENARIO=os-nosdn-openo-ha
+                COMPASS_OS_VERSION=xenial
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: true
+      - multijob:
+          name: functest
+          condition: SUCCESSFUL
+          projects:
+            - name: 'functest-compass-{pod}-suite-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                DEPLOY_SCENARIO=os-nosdn-openo-ha
+                FUNCTEST_SUITE_NAME=opera_vims
+              node-parameters: true
+              kill-phase-on: NEVER
+              abort-all-job: true
index 38efbc1..f866342 100644 (file)
@@ -1,3 +1,4 @@
+---
 - project:
 
     name: opera-project
@@ -5,12 +6,12 @@
     project: 'opera'
 
     stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
 
     jobs:
-        - 'opera-build-{stream}'
+      - 'opera-build-{stream}'
 
 ########################
 # job templates
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 1
-            max-per-node: 1
-            option: 'project'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 1
+          max-per-node: 1
+          option: 'project'
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'opnfv-build-ubuntu-defaults'
 
     scm:
-        - git-scm
+      - git-scm
 
     triggers:
-        - timed: 'H 23 * * *'
+      - timed: 'H 23 * * *'
 
     builders:
-        - 'opera-build-macro'
+      - 'opera-build-macro'
 
 #####################################
 # builder macros
@@ -49,9 +50,7 @@
 - builder:
     name: 'opera-build-macro'
     builders:
-        - shell: |
-            #!/bin/bash
-
-            echo "Hello world!"
-
+      - shell: |
+          #!/bin/bash
 
+          echo "Hello world!"
index 4da41d8..ad93d46 100644 (file)
@@ -1,30 +1,31 @@
+---
 - project:
     name: 'opera-verify-jobs'
 
     project: 'opera'
 
-#####################################
-# branch definitions
-#####################################
+    #####################################
+    # branch definitions
+    #####################################
     stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
-            disabled: false
-
-#####################################
-# patch verification phases
-#####################################
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
+
+    #####################################
+    # patch verification phases
+    #####################################
     phase:
-        - 'basic'
-        - 'deploy'
+      - 'basic'
+      - 'deploy'
 
-#####################################
-# jobs
-#####################################
+    #####################################
+    # jobs
+    #####################################
     jobs:
-        - 'opera-verify-{stream}'
-        - 'opera-verify-{phase}-{stream}'
+      - 'opera-verify-{stream}'
+      - 'opera-verify-{phase}-{stream}'
 #####################################
 # job templates
 #####################################
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-total: 1
-            max-per-node: 1
-            option: 'project'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 1
+          max-per-node: 1
+          option: 'project'
 
     scm:
-        - git-scm-gerrit
+      - git-scm-gerrit
 
     wrappers:
-        - ssh-agent-wrapper
-        - timeout:
-            timeout: 120
-            fail: true
+      - ssh-agent-wrapper
+      - timeout:
+          timeout: 120
+          fail: true
 
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - patchset-created-event:
-                    exclude-drafts: 'false'
-                    exclude-trivial-rebase: 'false'
-                    exclude-no-code-change: 'false'
-                - draft-published-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'recheck'
-                - comment-added-contains-event:
-                    comment-contains-value: 'reverify'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-                file-paths:
-                  - compare-type: ANT
-                    pattern: '**/*'
-                disable-strict-forbidden-file-verification: 'true'
-                forbidden-file-paths:
-                  - compare-type: ANT
-                    pattern: 'docs/**'
-            readable-message: true
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: 'recheck'
+            - comment-added-contains-event:
+                comment-contains-value: 'reverify'
+          projects:
+            - project-compare-type: 'ANT'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+              file-paths:
+                - compare-type: ANT
+                  pattern: '**/*'
+              disable-strict-forbidden-file-verification: 'true'
+              forbidden-file-paths:
+                - compare-type: ANT
+                  pattern: 'docs/**'
+          readable-message: true
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'huawei-pod7-defaults'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - 'huawei-pod7-defaults'
 
     builders:
-        - description-setter:
-            description: "Built on $NODE_NAME"
-        - multijob:
-            name: basic
-            condition: SUCCESSFUL
-            projects:
-                - name: 'opera-verify-basic-{stream}'
-                  current-parameters: true
-                  node-parameters: true
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
-        - multijob:
-            name: deploy
-            condition: SUCCESSFUL
-            projects:
-                - name: 'opera-verify-deploy-{stream}'
-                  current-parameters: true
-                  node-parameters: true
-                  kill-phase-on: FAILURE
-                  abort-all-job: true
+      - description-setter:
+          description: "Built on $NODE_NAME"
+      - multijob:
+          name: basic
+          condition: SUCCESSFUL
+          projects:
+            - name: 'opera-verify-basic-{stream}'
+              current-parameters: true
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: true
+      - multijob:
+          name: deploy
+          condition: SUCCESSFUL
+          projects:
+            - name: 'opera-verify-deploy-{stream}'
+              current-parameters: true
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: true
 
 - job-template:
     name: 'opera-verify-{phase}-{stream}'
     concurrent: true
 
     properties:
-        - logrotate-default
-        - throttle:
-            enabled: true
-            max-per-node: 1
-            option: 'project'
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-per-node: 1
+          option: 'project'
 
     scm:
-        - git-scm-gerrit
+      - git-scm-gerrit
 
     wrappers:
-        - ssh-agent-wrapper
-        - timeout:
-            timeout: 120
-            fail: true
+      - ssh-agent-wrapper
+      - timeout:
+          timeout: 120
+          fail: true
 
     builders:
-        - description-setter:
-            description: "Built on $NODE_NAME"
-        - '{project}-verify-{phase}-macro'
+      - description-setter:
+          description: "Built on $NODE_NAME"
+      - '{project}-verify-{phase}-macro'
 
 #####################################
 # builder macros
 - builder:
     name: 'opera-verify-basic-macro'
     builders:
-        - shell: |
-            #!/bin/bash
-            echo "Hello world!"
+      - shell: |
+          #!/bin/bash
+          echo "Hello world!"
 
 - builder:
     name: 'opera-verify-deploy-macro'
     builders:
-        - shell: |
-            #!/bin/bash
-            echo "Hello world!"
-
+      - shell: |
+          #!/bin/bash
+          echo "Hello world!"
index 864626b..f81feab 100644 (file)
@@ -1,14 +1,15 @@
+---
 - project:
     name: docs-rtd
     jobs:
-        - 'docs-merge-rtd-{stream}'
-        - 'docs-verify-rtd-{stream}'
+      - 'docs-merge-rtd-{stream}'
+      - 'docs-verify-rtd-{stream}'
 
     stream:
-        - master:
-            branch: 'master'
-        - danube:
-            branch: 'stable/{stream}'
+      - master:
+          branch: 'master'
+      - danube:
+          branch: 'stable/{stream}'
 
     project: 'opnfvdocs'
     rtdproject: 'opnfv'
     project-type: freestyle
 
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'lf-build1'
-            description: 'Slave label on Jenkins'
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
+      - label:
+          name: SLAVE_LABEL
+          default: 'lf-build1'
+          description: 'Slave label on Jenkins'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
 
     triggers:
-        - gerrit-trigger-change-merged:
-            project: '**'
-            branch: '{branch}'
-            files: 'docs/**/*.*'
+      - gerrit-trigger-change-merged:
+          project: '**'
+          branch: '{branch}'
+          files: 'docs/**/*.*'
 
     builders:
-        - shell: |
-            if [ $GERRIT_BRANCH == "master" ]; then
-              RTD_BUILD_VERSION=latest
-            else
-              RTD_BUILD_VERSION=${{GERRIT_BRANCH/\//-}}
-            fi
-            curl -X POST --data "version_slug=$RTD_BUILD_VERSION" https://readthedocs.org/build/opnfvdocsdemo
+      - shell: |
+          if [ $GERRIT_BRANCH == "master" ]; then
+            RTD_BUILD_VERSION=latest
+          else
+            RTD_BUILD_VERSION=${{GERRIT_BRANCH/\//-}}
+          fi
+          curl -X POST --data "version_slug=$RTD_BUILD_VERSION" https://readthedocs.org/build/opnfvdocsdemo
 
 
 - job-template:
     project-type: freestyle
 
     parameters:
-        - label:
-            name: SLAVE_LABEL
-            default: 'lf-build2'
-            description: 'Slave label on Jenkins'
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/opnfvdocs
-            description: 'Git URL to use on this Jenkins Slave'
+      - label:
+          name: SLAVE_LABEL
+          default: 'lf-build2'
+          description: 'Slave label on Jenkins'
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - string:
+          name: GIT_BASE
+          default: https://gerrit.opnfv.org/gerrit/opnfvdocs
+          description: 'Git URL to use on this Jenkins Slave'
+
     scm:
-        - git-scm-with-submodules:
-            branch: '{branch}'
+      - git-scm-with-submodules:
+          branch: '{branch}'
 
     triggers:
-        - gerrit-trigger-patchset-created:
-            server: 'gerrit.opnfv.org'
-            project: '**'
-            branch: '{branch}'
-            files: 'docs/**/*.*'
-        - timed: 'H H * * *'
+      - gerrit-trigger-patchset-created:
+          server: 'gerrit.opnfv.org'
+          project: '**'
+          branch: '{branch}'
+          files: 'docs/**/*.*'
+      - timed: 'H H * * *'
 
     builders:
-        - shell: |
-            if [ "$GERRIT_PROJECT" != "opnfvdocs" ]; then
-                cd docs/submodules/$GERRIT_PROJECT
-                git fetch origin $GERRIT_REFSPEC && git checkout FETCH_HEAD
-            else
-                git fetch origin $GERRIT_REFSPEC && git checkout FETCH_HEAD
-            fi
-        - shell: |
-            sudo pip install virtualenv 
-            virtualenv $WORKSPACE/venv
-            . $WORKSPACE/venv/bin/activate
-            pip install --upgrade pip
-            pip freeze
-            pip install tox
-            tox -edocs
+      - shell: |
+          if [ "$GERRIT_PROJECT" != "opnfvdocs" ]; then
+              cd docs/submodules/$GERRIT_PROJECT
+              git fetch origin $GERRIT_REFSPEC && git checkout FETCH_HEAD
+          else
+              git fetch origin $GERRIT_REFSPEC && git checkout FETCH_HEAD
+          fi
+      - shell: |
+          sudo pip install virtualenv
+          virtualenv $WORKSPACE/venv
+          . $WORKSPACE/venv/bin/activate
+          pip install --upgrade pip
+          pip freeze
+          pip install tox
+          tox -edocs
index fc825ff..6f63db9 100644 (file)
@@ -1,3 +1,4 @@
+---
 ########################
 # Job configuration for opnfvdocs
 ########################
@@ -8,19 +9,19 @@
     project: '{name}'
 
     jobs:
-        - 'opnfvdocs-verify-shellcheck-{stream}'
-        - 'opnfvdocs-merge-shellcheck-{stream}'
-        - 'opnfvdocs-daily-{stream}'
+      - 'opnfvdocs-verify-shellcheck-{stream}'
+      - 'opnfvdocs-merge-shellcheck-{stream}'
+      - 'opnfvdocs-daily-{stream}'
 
     stream:
-        - master:
-            branch: '{stream}'
-            gs-pathname: ''
-            disabled: false
-        - danube:
-            branch: 'stable/{stream}'
-            gs-pathname: '/{stream}'
-            disabled: false
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
+      - danube:
+          branch: 'stable/{stream}'
+          gs-pathname: '/{stream}'
+          disabled: false
 
 ########################
 # job templates
     disabled: '{obj:disabled}'
 
     parameters:
-        - project-parameter:
-            project: $GERRIT_PROJECT
-            branch: '{branch}'
-        - string:
-            name: GIT_CLONE_BASE
-            default: ssh://gerrit.opnfv.org:29418
-            description: "Used for overriding the GIT URL coming from parameters macro."
+      - project-parameter:
+          project: $GERRIT_PROJECT
+          branch: '{branch}'
+      - string:
+          name: GIT_CLONE_BASE
+          default: ssh://gerrit.opnfv.org:29418
+          description: "Used for overriding the GIT URL coming from parameters macro."
 
     scm:
-        - git-scm-gerrit
+      - git-scm-gerrit
 
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - patchset-created-event:
-                    exclude-drafts: 'false'
-                    exclude-trivial-rebase: 'false'
-                    exclude-no-code-change: 'false'
-                - draft-published-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'recheck'
-                - comment-added-contains-event:
-                    comment-contains-value: 'reverify'
-            projects:
-              - project-compare-type: 'REG_EXP'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-            skip-vote:
-                successful: true
-                failed: true
-                unstable: true
-                notbuilt: true
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: 'false'
+                exclude-trivial-rebase: 'false'
+                exclude-no-code-change: 'false'
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: 'recheck'
+            - comment-added-contains-event:
+                comment-contains-value: 'reverify'
+          projects:
+            - project-compare-type: 'REG_EXP'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
+          skip-vote:
+            successful: true
+            failed: true
+            unstable: true
+            notbuilt: true
 
     builders:
-        - check-bash-syntax
+      - check-bash-syntax
 
 - job-template:
     name: 'opnfvdocs-merge-shellcheck-{stream}'
     disabled: '{obj:disabled}'
 
     parameters:
-        - project-parameter:
-            project: $GERRIT_PROJECT
-            branch: '{branch}'
-        - string:
-            name: GIT_CLONE_BASE
-            default: ssh://gerrit.opnfv.org:29418
-            description: "Used for overriding the GIT URL coming from parameters macro."
-        - string:
-            name: GS_URL
-            default: '$GS_BASE{gs-pathname}'
-            description: "Directory where the build artifact will be located upon the completion of the build."
+      - project-parameter:
+          project: $GERRIT_PROJECT
+          branch: '{branch}'
+      - string:
+          name: GIT_CLONE_BASE
+          default: ssh://gerrit.opnfv.org:29418
+          description: "Used for overriding the GIT URL coming from parameters macro."
+      - string:
+          name: GS_URL
+          default: '$GS_BASE{gs-pathname}'
+          description: "Directory where the build artifact will be located upon the completion of the build."
 
     scm:
-        - git-scm
+      - git-scm
 
     triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - change-merged-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'remerge'
-            projects:
-              - project-compare-type: 'REG_EXP'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
+      - gerrit:
+          server-name: 'gerrit.opnfv.org'
+          trigger-on:
+            - change-merged-event
+            - comment-added-contains-event:
+                comment-contains-value: 'remerge'
+          projects:
+            - project-compare-type: 'REG_EXP'
+              project-pattern: '{project}'
+              branches:
+                - branch-compare-type: 'ANT'
+                  branch-pattern: '**/{branch}'
 
     builders:
-        - check-bash-syntax
+      - check-bash-syntax
 
 - job-template:
     name: 'opnfvdocs-daily-{stream}'
     disabled: true
 
     parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - string:
-            name: GS_URL
-            default: '$GS_BASE{gs-pathname}'
-            description: "Directory where the build artifact will be located upon the completion of the build."
-        - string:
-            name: GIT_CLONE_BASE
-            default: ssh://gerrit.opnfv.org:29418
-            description: "Used for overriding the GIT URL coming from parameters macro."
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - string:
+          name: GS_URL
+          default: '$GS_BASE{gs-pathname}'
+          description: "Directory where the build artifact will be located upon the completion of the build."
+      - string:
+          name: GIT_CLONE_BASE
+          default: ssh://gerrit.opnfv.org:29418
+          description: "Used for overriding the GIT URL coming from parameters macro."
 
     scm:
-        - git-scm
+      - git-scm
 
     triggers:
-        - timed: '0 H/6 * * *'
+      - timed: '0 H/6 * * *'
 
     builders:
-        - build-html-and-pdf-docs-output
-#        - upload-generated-docs-to-opnfv-artifacts
+      - build-html-and-pdf-docs-output
+#     - upload-generated-docs-to-opnfv-artifacts
index 1ea05c1..0722b40 100644 (file)
@@ -5,6 +5,7 @@ bottlenecks
 compass4nfv
 copper
 conductor
+container4nfv
 daisy
 doctor
 domino
@@ -24,7 +25,6 @@ movie
 multisite
 octopus
 onosfw
-openretriever
 ovno
 ovsnfv
 parser
diff --git a/jjb/orchestra/orchestra-daily-jobs.yml b/jjb/orchestra/orchestra-daily-jobs.yml
new file mode 100644 (file)
index 0000000..74c997c
--- /dev/null
@@ -0,0 +1,99 @@
+---
+###################################
+# job configuration for orchestra
+###################################
+- project:
+    name: 'orchestra-daily-jobs'
+
+    project: 'orchestra'
+
+    # -------------------------------
+    # BRANCH ANCHORS
+    # -------------------------------
+    master: &master
+      stream: master
+      branch: '{stream}'
+      gs-pathname: ''
+      disabled: false
+
+    # ------------------------------------------------------
+    # POD, INSTALLER, AND BRANCH MAPPING
+    # ------------------------------------------------------
+    pod:
+      - virtual:
+          slave-label: 'joid-virtual'
+          os-version: 'xenial'
+          <<: *master
+
+    jobs:
+      - 'orchestra-{pod}-daily-{stream}'
+
+################################
+# job template
+################################
+- job-template:
+    name: 'orchestra-{pod}-daily-{stream}'
+
+    project-type: multijob
+
+    disabled: '{obj:disabled}'
+
+    concurrent: false
+
+    properties:
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 1
+          max-per-node: 1
+          option: 'project'
+
+    scm:
+      - git-scm
+
+    wrappers:
+      - ssh-agent-wrapper
+
+      - timeout:
+          timeout: 240
+          fail: true
+
+    triggers:
+      - timed: '@daily'
+
+    parameters:
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - string:
+          name: DEPLOY_SCENARIO
+          default: os-nosdn-openbaton-ha
+      - '{slave-label}-defaults'
+
+    builders:
+      - description-setter:
+          description: "Built on $NODE_NAME"
+      - multijob:
+          name: deploy
+          condition: SUCCESSFUL
+          projects:
+            - name: 'joid-deploy-{pod}-daily-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                DEPLOY_SCENARIO=os-nosdn-openbaton-ha
+                COMPASS_OS_VERSION=xenial
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: true
+      - multijob:
+          name: functest
+          condition: SUCCESSFUL
+          projects:
+            - name: 'functest-joid-{pod}-daily-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                DEPLOY_SCENARIO=os-nosdn-openbaton-ha
+                FUNCTEST_SUITE_NAME=orchestra_ims
+              node-parameters: true
+              kill-phase-on: NEVER
+              abort-all-job: true
diff --git a/jjb/orchestra/orchestra-project-jobs.yml b/jjb/orchestra/orchestra-project-jobs.yml
new file mode 100644 (file)
index 0000000..60732ce
--- /dev/null
@@ -0,0 +1,49 @@
+---
+- project:
+
+    name: orchestra-project
+
+    project: 'orchestra'
+
+    stream:
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+
+    jobs:
+      - 'orchestra-build-{stream}'
+
+- job-template:
+    name: 'orchestra-build-{stream}'
+
+    concurrent: true
+
+    properties:
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 1
+          max-per-node: 1
+          option: 'project'
+
+    parameters:
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+
+    scm:
+      - git-scm
+
+    triggers:
+      - timed: 'H 23 * * *'
+
+    builders:
+      - 'orchestra-build-macro'
+
+- builder:
+    name: 'orchestra-build-macro'
+    builders:
+      - shell: |
+          #!/bin/bash
+
+          echo "Hello world!"
diff --git a/jjb/ovn4nfv/ovn4nfv-daily-jobs.yml b/jjb/ovn4nfv/ovn4nfv-daily-jobs.yml
new file mode 100644 (file)
index 0000000..a4c5865
--- /dev/null
@@ -0,0 +1,87 @@
+---
+- project:
+    name: 'ovn4nfv-daily-jobs'
+
+    project: 'ovn4nfv'
+
+    master: &master
+      stream: master
+      branch: '{stream}'
+      gs-pathname: ''
+      disabled: false
+
+    pod:
+      - virtual:
+          slave-label: 'joid-virtual'
+          os-version: 'xenial'
+          <<: *master
+
+    jobs:
+      - 'ovn4nfv-{pod}-daily-{stream}'
+
+- job-template:
+    name: 'ovn4nfv-{pod}-daily-{stream}'
+
+    project-type: multijob
+
+    disabled: '{obj:disabled}'
+
+    concurrent: false
+
+    properties:
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 1
+          max-per-node: 1
+          option: 'project'
+
+    scm:
+      - git-scm
+
+    wrappers:
+      - ssh-agent-wrapper
+
+      - timeout:
+          timeout: 240
+          fail: true
+
+    triggers:
+      - timed: '@daily'
+
+    parameters:
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+      - string:
+          name: DEPLOY_SCENARIO
+          default: os-ovn-nofeature-noha
+      - '{slave-label}-defaults'
+
+    builders:
+      - description-setter:
+          description: "Built on $NODE_NAME"
+      - multijob:
+          name: deploy
+          condition: SUCCESSFUL
+          projects:
+            - name: 'joid-deploy-{pod}-daily-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                DEPLOY_SCENARIO=os-ovn-nofeature-noha
+                COMPASS_OS_VERSION=xenial
+              node-parameters: true
+              kill-phase-on: FAILURE
+              abort-all-job: true
+      - multijob:
+          name: functest
+          condition: SUCCESSFUL
+          projects:
+            - name: 'functest-joid-{pod}-daily-{stream}'
+              current-parameters: false
+              predefined-parameters: |
+                DEPLOY_SCENARIO=os-ovn-nofeature-ha
+                FUNCTEST_SUITE_NAME=ovn4nfv_test_suite
+              node-parameters: true
+              kill-phase-on: NEVER
+              abort-all-job: true
diff --git a/jjb/ovn4nfv/ovn4nfv-project-jobs.yml b/jjb/ovn4nfv/ovn4nfv-project-jobs.yml
new file mode 100644 (file)
index 0000000..8c82cac
--- /dev/null
@@ -0,0 +1,52 @@
+---
+- project:
+    name: ovn4nfv
+
+    project: '{name}'
+
+
+    stream:
+      - master:
+          branch: '{stream}'
+          gs-pathname: ''
+          disabled: false
+
+    jobs:
+      - 'ovn4nfv-build-{stream}'
+
+- job-template:
+    name: 'ovn4nfv-build-{stream}'
+
+    concurrent: true
+
+    disabled: '{obj:disabled}'
+
+    properties:
+      - logrotate-default
+      - throttle:
+          enabled: true
+          max-total: 1
+          max-per-node: 1
+          option: 'project'
+
+    parametert:
+      - project-parameter:
+          project: '{project}'
+          branch: '{branch}'
+
+    scm:
+      - git-scm
+
+    triggers:
+      - timed: 'H 23 * * *'
+
+    builders:
+      - 'ovn4nfv-build-macro'
+
+- builder:
+    name: 'ovn4nfv-build-macro'
+    builders:
+      - shell: |
+          #!/bin/bash
+
+          echo "hello world"
index 0e8c713..62f6de0 100644 (file)
     publishers:
         - email:
             recipients: therbert@redhat.com mark.d.gray@intel.com billy.o.mahony@intel.com
+        - email-jenkins-admins-on-failure
 
 - builder:
     name: build-rpms
diff --git a/jjb/qtip/helpers/cleanup-deploy.sh b/jjb/qtip/helpers/cleanup-deploy.sh
deleted file mode 100644 (file)
index 9cb19a5..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-##############################################################################
-# Copyright (c) 2016 ZTE and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-# Remove previous running containers if exist
-if [[ ! -z $(docker ps -a | grep "opnfv/qtip:$DOCKER_TAG") ]]; then
-    echo "Removing existing opnfv/qtip containers..."
-    # workaround: sometimes it throws an error when stopping qtip container.
-    # To make sure ci job unblocked, remove qtip container by force without stopping it.
-    docker rm -f $(docker ps -a | grep "opnfv/qtip:$DOCKER_TAG" | awk '{print $1}')
-fi
-
-# Remove existing images if exist
-if [[ $(docker images opnfv/qtip:${DOCKER_TAG} | wc -l) -gt 1 ]]; then
-    echo "Removing docker image opnfv/qtip:$DOCKER_TAG..."
-    docker rmi opnfv/qtip:$DOCKER_TAG
-fi
diff --git a/jjb/qtip/helpers/validate-deploy.sh b/jjb/qtip/helpers/validate-deploy.sh
deleted file mode 100644 (file)
index af8f8c2..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-##############################################################################
-# Copyright (c) 2017 ZTE and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -e
-
-echo "--------------------------------------------------------"
-echo "POD: $NODE_NAME"
-echo "Scenario: $DEPLOY_SCENARIO"
-echo "INSTALLER: $INSTALLER_TYPE"
-echo "INSTALLER_IP: $INSTALLER_IP"
-echo "--------------------------------------------------------"
-
-echo "Qtip: Pulling docker image: opnfv/qtip:${DOCKER_TAG}"
-docker pull opnfv/qtip:$DOCKER_TAG >/dev/null
-
-envs="INSTALLER_TYPE=${INSTALLER_TYPE} -e INSTALLER_IP=${INSTALLER_IP}
--e POD_NAME=${NODE_NAME} -e SCENARIO=${DEPLOY_SCENARIO}"
-
-cmd=" docker run -id -e $envs opnfv/qtip:${DOCKER_TAG} /bin/bash"
-echo "Qtip: Running docker command: ${cmd}"
-${cmd}
-
-container_id=$(docker ps | grep "opnfv/qtip:${DOCKER_TAG}" | awk '{print $1}' | head -1)
-if [ $(docker ps | grep 'opnfv/qtip' | wc -l) == 0 ]; then
-    echo "The container opnfv/qtip with ID=${container_id} has not been properly started. Exiting..."
-    exit 1
-fi
-
-echo "The container ID is: ${container_id}"
-QTIP_REPO=/home/opnfv/repos/qtip
-
-docker exec -t ${container_id} bash -c "bash ${QTIP_REPO}/tests/ci/run_ci.sh"
-
-echo "Qtip done!"
-exit 0
\ No newline at end of file
diff --git a/jjb/qtip/helpers/validate-setup.sh b/jjb/qtip/helpers/validate-setup.sh
deleted file mode 100644 (file)
index 8d84e12..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env bash
-##############################################################################
-# Copyright (c) 2017 ZTE and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-
-set -e
-
-# setup virtualenv
-sudo pip install -u virtualenv virtualenvwrapper
-export WORKON_HOME=$HOME/.virtualenvs
-source /usr/local/bin/virtualenvwrapper.sh
-mkvirtualenv qtip
-workon qtip
-
-# setup qtip
-sudo pip install $HOME/repos/qtip
-
-# testing
-qtip --version
-qtip --help
diff --git a/jjb/qtip/qtip-experimental-jobs.yml b/jjb/qtip/qtip-experimental-jobs.yml
new file mode 100644 (file)
index 0000000..05445d8
--- /dev/null
@@ -0,0 +1,44 @@
+###########################################
+# Experimental jobs for development purpose
+###########################################
+
+- project:
+    name: qtip-experimental-jobs
+    project: qtip
+    jobs:
+        - 'qtip-experimental-{stream}'
+    stream:
+        - master:
+            branch: '{stream}'
+            gs-pathname: ''
+            disabled: false
+
+################################
+## job templates
+#################################
+
+- job-template:
+    name: 'qtip-experimental-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        # Pin the tests on zte-pod4 with apex deployment
+        - apex-defaults
+        - zte-pod4-defaults
+    scm:
+        - git-scm-gerrit
+
+    triggers:
+        - experimental:
+            project: '{project}'
+            branch: '{branch}'
+            files: '**'
+
+    builders:
+        - shell: |
+             #!/bin/bash
+                source tests/ci/experimental.sh
index 8dd97de..e64173c 100644 (file)
         branch: '{stream}'
         gs-pathname: ''
         docker-tag: latest
-    danube: &danube
-        stream: danube
-        branch: 'stable/{stream}'
-        gs-pathname: '/{stream}'
-        docker-tag: 'stable'
 
 #--------------------------------
 # JOB VARIABLES
 #--------------------------------
-    pod:
-        - zte-pod1:
-            installer: fuel
-            scenario: os-odl_l2-nofeature-ha
+    qpi:
+        - compute:
+            installer: apex
+            pod: zte-pod4
             <<: *master
-        - zte-pod3:
-            installer: fuel
-            scenario: os-nosdn-kvm-ha
+        - storage:
+            installer: apex
+            pod: zte-pod4
             <<: *master
-        - zte-pod1:
-            installer: fuel
-            scenario: os-odl_l2-nofeature-ha
-            <<: *danube
-        - zte-pod3:
-            installer: fuel
-            scenario: os-nosdn-nofeature-ha
-            <<: *danube
-        - zte-pod3:
-            installer: fuel
-            scenario: os-nosdn-kvm-ha
-            <<: *danube
 
 #--------------------------------
 # JOB LIST
 #--------------------------------
     jobs:
-        - 'qtip-{scenario}-{pod}-daily-{stream}'
+        - 'qtip-{qpi}-{installer}-{stream}'
 
 ################################
 # job templates
 ################################
 - job-template:
-    name: 'qtip-{scenario}-{pod}-daily-{stream}'
+    name: 'qtip-{qpi}-{installer}-{stream}'
     disabled: false
     parameters:
         - project-parameter:
@@ -64,7 +47,7 @@
         - '{pod}-defaults'
         - string:
             name: DEPLOY_SCENARIO
-            default: '{scenario}'
+            default: generic
         - string:
             name: DOCKER_TAG
             default: '{docker-tag}'
             name: CI_DEBUG
             default: 'false'
             description: "Show debug output information"
+        - string:
+            name: TEST_SUITE
+            default: '{qpi}'
     scm:
         - git-scm
     triggers:
-        - 'qtip-{scenario}-{pod}-daily-{stream}-trigger'
+        - 'qtip-daily'
     builders:
         - description-setter:
             description: "POD: $NODE_NAME"
-        - qtip-validate-deploy
+        - shell: |
+            #!/bin/bash
+            source tests/ci/periodic.sh
     publishers:
         - qtip-common-publishers
+        - email-jenkins-admins-on-failure
 
 ################
 # MARCOS
 #---------
 # builder
 #---------
-- builder:
-    name: qtip-validate-deploy
-    builders:
-        - shell:
-            !include-raw: ./helpers/cleanup-deploy.sh
-        - shell:
-            !include-raw: ./helpers/validate-deploy.sh
-
 
 #-----------
 # parameter
 #---------
 
 - trigger:
-    name: 'qtip-os-odl_l2-nofeature-ha-zte-pod1-daily-master-trigger'
-    triggers:
-        - timed: '0 15 * * *'
-
-- trigger:
-    name: 'qtip-os-nosdn-kvm-ha-zte-pod3-daily-master-trigger'
+    name: 'qtip-daily'
     triggers:
         - timed: '0 15 * * *'
-
-- trigger:
-    name: 'qtip-os-odl_l2-nofeature-ha-zte-pod1-daily-danube-trigger'
-    triggers:
-        - timed: '0 7 * * *'
-
-- trigger:
-    name: 'qtip-os-nosdn-kvm-ha-zte-pod3-daily-danube-trigger'
-    triggers:
-        - timed: '0 7 * * *'
-
-- trigger:
-    name: 'qtip-os-nosdn-nofeature-ha-zte-pod3-daily-danube-trigger'
-    triggers:
-        - timed: '30 0 * * *'
index dd444c7..a273c85 100644 (file)
@@ -7,6 +7,8 @@
     project: qtip
     jobs:
         - 'qtip-verify-{stream}'
+        - 'qtip-review-notebook-{stream}'
+        - 'qtip-merge-{stream}'
     stream:
         - master:
             branch: '{stream}'
         - qtip-unit-tests-and-docs-build
     publishers:
         - publish-coverage
+        - email-jenkins-admins-on-failure
+
+# upload juypter notebook to artifacts for review
+- job-template:
+    name: 'qtip-review-notebook-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - 'opnfv-build-ubuntu-defaults'
+
+    scm:
+        - git-scm-gerrit
+
+    triggers:
+        - gerrit:
+            server-name: 'gerrit.opnfv.org'
+            trigger-on:
+                - patchset-created-event:
+                    exclude-drafts: 'false'
+                    exclude-trivial-rebase: 'false'
+                    exclude-no-code-change: 'false'
+                - draft-published-event
+                - comment-added-contains-event:
+                    comment-contains-value: 'recheck'
+                - comment-added-contains-event:
+                    comment-contains-value: 'reverify'
+            projects:
+              - project-compare-type: 'ANT'
+                project-pattern: '{project}'
+                branches:
+                  - branch-compare-type: 'ANT'
+                    branch-pattern: '**/{branch}'
+                disable-strict-forbidden-file-verification: 'true'
+                file-paths:
+                  - compare-type: ANT
+                    pattern: 'examples/**'
+    builders:
+        - upload-under-review-notebooks-to-opnfv-artifacts
+        - report-build-result-to-gerrit
+
+- job-template:
+    name: 'qtip-merge-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    parameters:
+        - project-parameter:
+            project: $GERRIT_PROJECT
+            branch: '{branch}'
+        - string:
+            name: GS_URL
+            default: '$GS_BASE{gs-pathname}'
+            description: "Directory where the build artifact will be located upon the completion of the build."
+        - string:
+            name: GERRIT_REFSPEC
+            default: 'refs/heads/{branch}'
+            description: "JJB configured GERRIT_REFSPEC parameter"
+
+    scm:
+        - git-scm
+
+    triggers:
+        - gerrit:
+            server-name: 'gerrit.opnfv.org'
+            trigger-on:
+                - change-merged-event
+                - comment-added-contains-event:
+                    comment-contains-value: 'remerge'
+            projects:
+                - project-compare-type: 'ANT'
+                  project-pattern: '*'
+                  branches:
+                      - branch-compare-type: 'ANT'
+                        branch-pattern: '**/{branch}'
+                  file-paths:
+                      - compare-type: ANT
+                        pattern: examples/**
+
+    builders:
+        - remove-old-docs-from-opnfv-artifacts
 
 ################################
 ## job builders
             set -o xtrace
 
             tox
+
+# modified from upload-under-review-docs-to-opnfv-artifacts in global/releng-macro.yml
+- builder:
+    name: upload-under-review-notebooks-to-opnfv-artifacts
+    builders:
+        - shell: |
+            #!/bin/bash
+            set -o errexit
+            set -o pipefail
+            set -o xtrace
+            export PATH=$PATH:/usr/local/bin/
+
+            [[ $GERRIT_CHANGE_NUMBER =~ .+ ]]
+            [[ -d examples ]] || exit 0
+
+            echo
+            echo "###########################"
+            echo "UPLOADING DOCS UNDER REVIEW"
+            echo "###########################"
+            echo
+
+            gs_base="artifacts.opnfv.org/$PROJECT/review"
+            gs_path="$gs_base/$GERRIT_CHANGE_NUMBER"
+            local_path="upload/$GERRIT_CHANGE_NUMBER"
+
+            mkdir -p upload
+            cp -r examples "$local_path"
+            gsutil -m cp -r "$local_path" "gs://$gs_base/"
+
+            echo "Document link(s):" >> gerrit_comment.txt
+            find "$local_path" | grep -e 'ipynb$' | \
+                sed -e "s|^$local_path|    https://nbviewer.jupyter.org/url/$gs_path|" >> gerrit_comment.txt
index 9eb281d..c6ca37f 100644 (file)
 
     builders:
         - shell: |
-            bash ./utils/test/{module}/run_test.sh
+            cd ./utils/test/{module}/
+            tox
+            if [ -e *.xml ];then
+                cp *.xml $WORKSPACE
+            fi
 
     publishers:
-        - junit:
-            results: nosetests.xml
-        - cobertura:
-            report-file: "coverage.xml"
-            only-stable: "true"
-            health-auto-update: "false"
-            stability-auto-update: "false"
-            zoom-coverage-chart: "true"
-            targets:
-                - files:
-                    healthy: 10
-                    unhealthy: 20
-                    failing: 30
-                - method:
-                    healthy: 50
-                    unhealthy: 40
-                    failing: 30
+        - publish-coverage
+        - email-jenkins-admins-on-failure
 
 - job-template:
     name: '{module}-automate-{stream}'
 
     publishers:
         - 'email-publisher'
+        - email-jenkins-admins-on-failure
 
 - job-template:
     name: '{module}-automate-{phase}-{stream}'
     name: 'testapi-automate-docker-deploy-macro'
     builders:
         - shell: |
-            bash ./jjb/releng/docker-deploy.sh 'sudo docker run -dti -p 8082:8000 -e mongodb_url=mongodb://172.17.0.1:27017 -e swagger_url=http://testresults.opnfv.org/test opnfv/testapi' "http://testresults.opnfv.org/test/swagger/APIs"
+            sudo bash ./jjb/releng/docker-deploy.sh "sudo docker run -dti --name testapi -p 8082:8000
+            -e mongodb_url=mongodb://172.17.0.1:27017
+            -e base_url=http://testresults.opnfv.org/test opnfv/testapi" \
+            "http://testresults.opnfv.org/test/" "testapi"
+
 - builder:
     name: 'reporting-automate-docker-deploy-macro'
     builders:
         - shell: |
-            bash ./jjb/releng/docker-deploy.sh 'sudo docker run -itd -p 8084:8000 -e SERVER_URL=http://testresults.opnfv.org/reporting2:8084 opnfv/reporting' "http://testresults.opnfv.org/reporting2/reporting/index.html"
+            sudo bash ./jjb/releng/docker-deploy.sh "sudo docker run -itd --name reporting -p 8084:8000 opnfv/reporting" \
+            "http://testresults.opnfv.org/reporting2/reporting/index.html" "reporting"
 
 - builder:
     name: mongodb-backup
index b3b930f..1e83577 100644 (file)
 #  specific language governing permissions and limitations      *
 #  under the License.                                           *
 
-# Assigning Variables
+
 command=$1
 url=$2
+module=$3
+
+REPO="opnfv"
+latest_image=$REPO/$module:latest
+old_image=$REPO/$module:old
+latest_container_name=$module
+old_container_name=$module"_old"
+latest_container_id=
+old_container_id=
+new_start_container=
+
+function DEBUG() {
+  echo `date "+%Y-%m-%d %H:%M:%S.%N"` ": $1"
+}
 
-function check() {
-
-    # Verify hosted
+function check_connectivity() {
+    # check update status via test the connectivity of provide url
     sleep 5
     cmd=`curl -s --head  --request GET ${url} | grep '200 OK' > /dev/null`
     rc=$?
-    echo $rc
-
-    if [[ $rc == 0 ]]
-    then
+    DEBUG $rc
+    if [[ $rc == 0 ]]; then
         return 0
     else
         return 1
     fi
-
 }
 
-echo "Getting contianer Id of the currently running one"
-contId=$(sudo docker ps | grep "opnfv/testapi:latest" | awk '{print $1}')
 
-echo "Pulling the latest image"
-sudo docker pull opnfv/testapi:latest
+function pull_latest_image() {
+    DEBUG "pull latest image $latest_image"
+    docker pull $latest_image
+}
 
-echo "Deleting old containers of opnfv/testapi:old"
-sudo docker ps -a | grep "opnfv/testapi" | grep "old" | awk '{print $1}' | xargs -r sudo docker rm -f
+function get_latest_running_container() {
+    latest_container_id=`docker ps -q --filter name=^/$latest_container_name$`
+}
 
-echo "Deleting old images of opnfv/testapi:latest"
-sudo docker images | grep "opnfv/testapi" | grep "old" | awk '{print $3}' | xargs -r sudo docker rmi -f
+function get_old_running_container() {
+    old_container_id=`docker ps -q --filter name=^/$old_container_name$`
+}
 
+function delete_old_image() {
+    DEBUG "delete old image: $old_image"
+    docker rmi -f $old_image
+}
 
-if [[ -z "$contId" ]]
-then
-    echo "No running testapi container"
+function delete_old_container() {
+    DEBUG "delete old container: $old_container_name"
+    docker ps -a -q --filter name=^/$old_container_name$ | xargs docker rm -f &>/dev/null
+}
 
-    echo "Removing stopped testapi containers in the previous iterations"
-    sudo docker ps -f status=exited | grep "opnfv_testapi" | awk '{print $1}' | xargs -r sudo docker rm -f
-else
-    echo $contId
+function delete_latest_container() {
+    DEBUG "delete latest container: $module"
+    docker ps -a -q --filter name=^/$latest_container_name$ | xargs docker rm -f &>/dev/null
+}
 
-    echo "Get the image id of the currently running conatiner"
-    currImgId=$(sudo docker ps | grep "$contId" | awk '{print $2}')
-    echo $currImgId
+function delete_latest_image() {
+    DEBUG "delete latest image: $REPO/$module:latest"
+    docker rmi -f $latest_image
+}
 
-    if [[ -z "$currImgId" ]]
-    then
-        echo "No image id found for the container id"
-        exit 1
-    fi
+function change_image_tag_2_old() {
+    DEBUG "change image tag 2 old"
+    docker tag $latest_image $old_image
+    docker rmi -f $latest_image
+}
 
-    echo "Changing current image tag to old"
-    sudo docker tag "$currImgId" opnfv/testapi:old
+function mark_latest_container_2_old() {
+    DEBUG "mark latest container to be old"
+    docker rename "$latest_container_name" "$old_container_name"
+}
 
-    echo "Removing stopped testapi containers in the previous iteration"
-    sudo docker ps -f status=exited | grep "opnfv_testapi" | awk '{print $1}' | xargs -r sudo docker rm -f
+function stop_old_container() {
+    DEBUG "stop old container"
+    docker stop "$old_container_name"
+}
 
-    echo "Renaming the running container name to opnfv_testapi as to identify it."
-    sudo docker rename $contId opnfv_testapi
+function run_latest_image() {
+    new_start_container=`$command`
+    DEBUG "run latest image: $new_start_container"
+}
 
-    echo "Stop the currently running container"
-    sudo docker stop $contId
+get_latest_running_container
+get_old_running_container
+
+if [[ ! -z $latest_container_id ]]; then
+    DEBUG "latest container is running: $latest_container_id"
+    delete_old_container
+    delete_old_image
+    change_image_tag_2_old
+    mark_latest_container_2_old
+    pull_latest_image
+    stop_old_container
+    run_latest_image
+
+elif [[ ! -z $old_container_id ]]; then
+    DEBUG "old container is running: $old_container_id"
+    delete_latest_container
+    delete_latest_image
+    pull_latest_image
+    stop_old_container
+    run_latest_image
+else
+    DEBUG "no container is running"
+    delete_old_container
+    delete_old_image
+    delete_latest_container
+    delete_latest_image
+    pull_latest_image
+    run_latest_image
 fi
 
-echo "Running a container with the new image"
-$command:latest
-
-if check; then
-    echo "TestResults Hosted."
+if check_connectivity; then
+    DEBUG "CONGRATS: $module update successfully"
 else
-    echo "TestResults Hosting Failed"
-    if [[ $(sudo docker images | grep "opnfv/testapi" | grep "old" | awk '{print $3}') ]]; then
-        echo "Running old Image"
-        $command:old
-        exit 1
+    DEBUG "ATTENTION: $module update failed"
+    id=`docker ps -a -q --filter name=^/$old_container_name$`
+    if [[ ! -z $id ]]; then
+        DEBUG "start old container instead"
+        docker stop $new_start_container
+        docker start $id
+    fi
+    if ! check_connectivity; then
+        DEBUG "BIG ISSUE: no container is running normally"
     fi
+    exit 1
 fi
 
-# Echo Images and Containers
-sudo docker images
-sudo docker ps -a
+docker images
+docker ps -a
diff --git a/jjb/releng/generate-job-list.sh b/jjb/releng/generate-job-list.sh
new file mode 100755 (executable)
index 0000000..4bf8974
--- /dev/null
@@ -0,0 +1,70 @@
+#!/bin/bash
+# SPDX-license-identifier: Apache-2.0
+##############################################################################
+# Copyright (c) 2016 Linux Foundation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+set -o errexit
+set -o pipefail
+
+# Job Number Formatter
+function JOBS {
+    local NUMS=$1
+    if [ $NUMS == 1 ]; then
+        echo -n "Job"
+    else
+        echo -n "Jobs"
+    fi
+}
+
+# Activiate the virtualenv so we have access to 'jenkins-jobs'
+source /opt/virtualenv/jenkins-job-builder/bin/activate
+
+echo "> Generating list of current JJB jobs..."
+jenkins-jobs -l ERROR test -r jjb -o job_output
+
+echo "> Generating list of previous JJB jobs..."
+git checkout -b previous-commit HEAD^
+jenkins-jobs -l ERROR test -r jjb -o job_output_prev
+git checkout - && git branch -d previous-commit
+
+echo "> Finding job changes ..."
+diff -r -q job_output job_output_prev &> job_diff.txt || true
+
+# Only in (job_output) = NEW
+# Only in (job_output_prev) = DELETED
+# Files ... differ = MODIFIED
+
+declare -a JOBS_ADDED=($(grep 'job_output:' job_diff.txt | cut -d':' -f2- | sed 's/^[ \t]*//;s/[ \t]*$//'))
+declare -a JOBS_MODIFIED=($(grep 'differ$' job_diff.txt | sed "s/Files job_output\/\(.*\) and.*/\1/g"))
+declare -a JOBS_REMOVED=($(grep 'job_output_prev:' job_diff.txt | cut -d ':' -f2- | sed 's/^[ \t]*//;s/[ \t]*$//'))
+
+NUM_JOBS_ADDED=${#JOBS_ADDED[@]}
+NUM_JOBS_MODIFIED=${#JOBS_MODIFIED[@]}
+NUM_JOBS_REMOVED=${#JOBS_REMOVED[@]}
+
+echo "> Writing gerrit comment ..."
+if [ $NUM_JOBS_ADDED -gt 0 ]; then
+    JOB_STRING="$(JOBS $NUM_JOBS_ADDED)"
+    { printf "Added %s %s:\n\n" "${NUM_JOBS_ADDED}" "$JOB_STRING";
+    printf '* %s\n' "${JOBS_ADDED[@]}";
+    printf "\n"; } >> gerrit_comment.txt
+fi
+
+if [ $NUM_JOBS_MODIFIED -gt 0 ]; then
+    JOB_STRING="$(JOBS $NUM_JOBS_MODIFIED)"
+    { printf "Modified %s %s:\n\n" "${NUM_JOBS_MODIFIED}" "$JOB_STRING";
+    printf '* %s\n' "${JOBS_MODIFIED[@]}";
+    printf "\n"; } >> gerrit_comment.txt
+fi
+
+if [ $NUM_JOBS_REMOVED -gt 0 ]; then
+    JOB_STRING="$(JOBS $NUM_JOBS_REMOVED)"
+    { printf "Removed %s %s:\n\n" "${NUM_JOBS_REMOVED}" "$JOB_STRING";
+    printf '* %s\n' "${JOBS_REMOVED[@]}";
+    printf "\n"; } >> gerrit_comment.txt
+fi
index 417fc70..842d496 100644 (file)
             cristina.pauna@enea.com
             alexandru.avadanii@enea.com
             alexandru.nemes@enea.com
+    yardstick-arm-receivers: &yardstick-arm-receivers
+        receivers: >
+            cristina.pauna@enea.com
+            alexandru.avadanii@enea.com
+            alexandru.nemes@enea.com
+            catalina.focsa@enea.com
     other-receivers: &other-receivers
         receivers: ''
 
@@ -34,6 +40,9 @@
         - 'dovetail':
             <<: *master
             <<: *dovetail-arm-receivers
+        - 'yardstick':
+            <<: *master
+            <<: *yardstick-arm-receivers
         # projects with jobs for stable
 
     jobs:
             name: RELEASE_VERSION
             default: ""
             description: "Release version, e.g. 1.0, 2.0, 3.0"
+        - string:
+            name: DOCKER_DIR
+            default: "docker"
+            description: "Directory containing files needed by the Dockerfile"
         - string:
             name: DOCKERFILE
             default: "Dockerfile.aarch64"
@@ -83,3 +96,4 @@
     publishers:
         - email:
             recipients: '{receivers}'
+        - email-jenkins-admins-on-failure
index ebd0c9f..0de3df2 100644 (file)
@@ -54,7 +54,7 @@ if [[ -n "$(docker images | grep $DOCKER_REPO_NAME)" ]]; then
     done
 fi
 
-cd $WORKSPACE/docker
+cd $WORKSPACE/$DOCKER_DIR
 HOST_ARCH=$(uname -m)
 if [ ! -f "${DOCKERFILE}" ]; then
     # If this is expected to be a Dockerfile for other arch than x86
index 095ba41..414eba2 100644 (file)
     other-receivers: &other-receivers
         receivers: ''
 
-    project:
+    dockerfile: "Dockerfile"
+    dockerdir: "docker"
+
+    # This is the dockerhub repo the image will be pushed to as
+    # 'opnfv/{dockerrepo}. See: DOCKER_REPO_NAME parameter.
+    # 'project' is the OPNFV repo we expect to contain the Dockerfile
+    dockerrepo:
         # projects with jobs for master
         - 'releng-anteater':
+            project: 'releng-anteater'
             <<: *master
             <<: *other-receivers
         - 'bottlenecks':
+            project: 'bottlenecks'
             <<: *master
             <<: *other-receivers
         - 'cperf':
+            project: 'cperf'
             <<: *master
             <<: *other-receivers
         - 'dovetail':
+            project: 'dovetail'
             <<: *master
             <<: *other-receivers
         - 'functest':
+            project: 'functest'
             <<: *master
             <<: *functest-receivers
         - 'qtip':
+            project: 'qtip'
             <<: *master
             <<: *other-receivers
-        - 'storperf':
+        - 'storperf-master':
+            project: 'storperf'
+            dockerdir: 'docker/storperf-master'
+            <<: *master
+            <<: *other-receivers
+        - 'storperf-graphite':
+            project: 'storperf'
+            dockerdir: 'docker/storperf-graphite'
+            <<: *master
+            <<: *other-receivers
+        - 'storperf-httpfrontend':
+            project: 'storperf'
+            dockerdir: 'docker/storperf-httpfrontend'
+            <<: *master
+            <<: *other-receivers
+        - 'storperf-reporting':
+            project: 'storperf'
+            dockerdir: 'docker/storperf-reporting'
+            <<: *master
+            <<: *other-receivers
+        - 'storperf-swaggerui':
+            project: 'storperf'
+            dockerdir: 'docker/storperf-swaggerui'
             <<: *master
             <<: *other-receivers
         - 'yardstick':
+            project: 'yardstick'
             <<: *master
             <<: *other-receivers
         # projects with jobs for stable
         - 'bottlenecks':
+            project: 'bottlenecks'
             <<: *danube
             <<: *other-receivers
         - 'functest':
+            project: 'functest'
             <<: *danube
             <<: *functest-receivers
         - 'qtip':
+            project: 'qtip'
             <<: *danube
             <<: *other-receivers
         - 'storperf':
+            project: 'storperf'
             <<: *danube
             <<: *other-receivers
         - 'yardstick':
+            project: 'yardstick'
             <<: *danube
             <<: *other-receivers
 
     jobs:
-        - '{project}-docker-build-push-{stream}'
+        - "{dockerrepo}-docker-build-push-{stream}"
 
 
 - project:
 
     name: opnfv-monitor-docker        # projects which only monitor dedicated file or path
 
+    dockerfile: "Dockerfile"
+    dockerdir: "docker"
+
     project:
         # projects with jobs for master
         - 'daisy':
+            dockerrepo: 'daisy'
             <<: *master
         - 'escalator':
+            dockerrepo: 'escalator'
             <<: *master
 
     jobs:
 # job templates
 ########################
 - job-template:
-    name: '{project}-docker-build-push-{stream}'
+    name: '{dockerrepo}-docker-build-push-{stream}'
 
     disabled: '{obj:disabled}'
 
             description: "To enable/disable pushing the image to Dockerhub."
         - string:
             name: DOCKER_REPO_NAME
-            default: "opnfv/{project}"
+            default: "opnfv/{dockerrepo}"
             description: "Dockerhub repo to be pushed to."
+        - string:
+            name: DOCKER_DIR
+            default: "{dockerdir}"
+            description: "Directory containing files needed by the Dockerfile"
         - string:
             name: COMMIT_ID
             default: ""
             description: "Release version, e.g. 1.0, 2.0, 3.0"
         - string:
             name: DOCKERFILE
-            default: "Dockerfile"
+            default: "{dockerfile}"
             description: "Dockerfile to use for creating the image."
 
     scm:
     publishers:
         - email:
             recipients: '{receivers}'
+        - email-jenkins-admins-on-failure
 
 - job-template:
     name: '{project}-docker-build-push-monitor-{stream}'
index 8c231c3..d253da0 100644 (file)
@@ -53,7 +53,7 @@
                     comment-contains-value: 'reverify'
             projects:
               - project-compare-type: 'REG_EXP'
-                project-pattern: 'functest|sdnvpn|qtip|daisy|sfc|escalator|releng|pharos|octopus|securedlab'
+                project-pattern: 'functest|sdnvpn|qtip|daisy|sfc|escalator|releng'
                 branches:
                   - branch-compare-type: 'ANT'
                     branch-pattern: '**/{branch}'
                     comment-contains-value: 'reverify'
             projects:
               - project-compare-type: 'REG_EXP'
-                project-pattern: ''
+                project-pattern: 'octopus|releng-anteater|pharos'
                 branches:
                   - branch-compare-type: 'ANT'
                     branch-pattern: '**/{branch}'
diff --git a/jjb/releng/opnfv-repo-archiver.sh b/jjb/releng/opnfv-repo-archiver.sh
new file mode 100644 (file)
index 0000000..c9fdba3
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+# SPDX-license-identifier: Apache-2.0
+##############################################################################
+# Copyright (c) 2016 Linux Foundation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+set -o errexit
+set -o pipefail
+export PATH=$PATH:/usr/local/bin/
+
+DATE="$(date +%Y%m%d)"
+
+declare -a PROJECT_LIST
+EXCLUDE_PROJECTS="All-Projects|All-Users|securedlab"
+CLONE_PATH="$WORKSPACE/opnfv-repos"
+
+# Generate project list from gerrit
+PROJECT_LIST=($(ssh -p 29418 jenkins-ci@gerrit.opnfv.org gerrit ls-projects | egrep -v $EXCLUDE_PROJECTS))
+
+echo "Cloning all OPNFV repositories"
+echo "------------------------------"
+
+for PROJECT in "${PROJECT_LIST[@]}"; do
+  echo "> Cloning $PROJECT"
+  if [ ! -d "$CLONE_PATH/$PROJECT" ]; then
+    git clone "https://gerrit.opnfv.org/gerrit/$PROJECT.git" $CLONE_PATH/$PROJECT
+  else
+    pushd "$CLONE_PATH/$PROJECT" &>/dev/null
+    git pull -f
+    popd &> /dev/null
+  fi
+
+  # Don't license scan kernel or qemu in kvmfornfv
+  if [ "$PROJECT" == "kvmfornfv" ]; then
+    rm -rf "$CLONE_PATH/$PROJECT/{kernel,qemu}"
+  fi
+done
+
+echo "Finished cloning OPNFV repositories"
+echo "-----------------------------------"
+
+# Copy repos and clear git data
+echo "Copying repos to $WORKSPACE/opnfv-archive and removing .git files"
+cp -R $CLONE_PATH $WORKSPACE/opnfv-archive
+find $WORKSPACE/opnfv-archive -type d -iname '.git' -exec rm -rf {} +
+find $WORKSPACE/opnfv-archive -type f -iname '.git*' -exec rm -rf {} +
+
+# Create archive
+echo "Creating archive: opnfv-archive-$DATE.tar.gz"
+echo "--------------------------------------"
+cd $WORKSPACE
+tar -czf "opnfv-archive-$DATE.tar.gz" opnfv-archive && rm -rf opnfv-archive
+echo "Archiving Complete."
+
+echo "Uploading artifacts"
+echo "--------------------------------------"
+
+gsutil cp "$WORKSPACE/opnfv-archive-$DATE.tar.gz" \
+    "gs://opnfv-archive/opnfv-archive-$DATE.tar.gz" 2>&1
+
+rm -f opnfv-archive-$DATE.tar.gz
+
+echo "Finished"
index 717bb3c..721b5de 100644 (file)
@@ -4,6 +4,9 @@
 
     jobs:
         - 'prune-docker-images'
+        - 'archive-repositories'
+        - 'check-status-of-slaves'
+
 ########################
 # job templates
 ########################
 
     triggers:
         - timed: '@midnight'
+
+- job-template:
+    name: 'archive-repositories'
+
+    disabled: false
+
+    concurrent: true
+
+    parameters:
+        - node:
+            name: SLAVE_NAME
+            description: Where to create the archive
+            default-slaves:
+                - master
+            allowed-multiselect: false
+            ignore-offline-nodes: true
+
+    triggers:
+        - timed: '@monthly'
+
+    builders:
+        - shell:
+            !include-raw-escape: opnfv-repo-archiver.sh
+
+- job-template:
+    name: 'check-status-of-slaves'
+
+    disabled: false
+
+    concurrent: true
+
+    parameters:
+        - node:
+            name: SLAVE_NAME
+            description: We don't want workspace wiped. so I just threw the script on the master
+            default-slaves:
+                - master
+            allowed-multiselect: false
+            ignore-offline-nodes: true
+
+    triggers:
+        - timed: '@midnight'
+
+    builders:
+        - shell: |
+            cd /opt/jenkins-ci/slavemonitor
+            bash slave-monitor-0.1.sh | sort
index ecc8730..fd58ef2 100644 (file)
@@ -3,6 +3,7 @@
     jobs:
         - 'releng-verify-jjb'
         - 'releng-merge-jjb'
+        - 'releng-comment-jjb'
         - 'releng-generate-artifacts-api'
 
     project: 'releng'
     publishers:
         - archive-artifacts:
             artifacts: 'job_output/*'
+        - email-jenkins-admins-on-failure
+
+- job-template:
+    name: releng-comment-jjb
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: 'master'
+    scm:
+        - git-scm-gerrit
+
+    triggers:
+        - experimental:
+            project: '{project}'
+            branch: 'master'
+            files: 'jjb/**'
+
+    builders:
+        - shell:
+            !include-raw-escape: generate-job-list.sh
+        - report-build-result-to-gerrit
 
 - job-template:
     name: 'releng-merge-jjb'
index 1e85536..430ced5 100644 (file)
                     pattern: '**/*.jinja2'
                   - compare-type: ANT
                     pattern: '**/*.yaml'
+            skip-vote:
+                successful: true
+                failed: true
+                unstable: true
+                notbuilt: true
+
     builders:
         - check-jinja
 
similarity index 81%
rename from jjb/multisite/multisite-verify-jobs.yml
rename to jjb/sfc/sfc-project-jobs.yml
index 9431e0b..379fe79 100644 (file)
@@ -3,38 +3,32 @@
 # They will only be enabled on request by projects!
 ###################################################
 - project:
-    name: multisite
+    name: sfc-project-jobs
 
-    project: '{name}'
+    project: 'sfc'
 
     jobs:
-        - 'multisite-verify-{stream}'
-
+        - 'sfc-verify-{stream}'
     stream:
         - master:
             branch: '{stream}'
             gs-pathname: ''
             disabled: false
-            timed: '@midnight'
         - danube:
             branch: 'stable/{stream}'
             gs-pathname: '/{stream}'
-            disabled: false
-            timed: ''
+            disabled: true
 
 - job-template:
-    name: 'multisite-verify-{stream}'
+    name: 'sfc-verify-{stream}'
 
     disabled: '{obj:disabled}'
 
-    concurrent: true
-
     parameters:
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
         - 'opnfv-build-ubuntu-defaults'
-
     scm:
         - git-scm-gerrit
 
                     pattern: 'docs/**|.gitignore'
 
     builders:
-        - shell: |
-            #!/bin/bash
+        - sfc-unit-tests
+
+################################
+# job builders
+################################
 
-            echo "Hello World"
+- builder:
+    name: sfc-unit-tests
+    builders:
+        - shell: |
+            cd $WORKSPACE && yamllint $(git ls-tree -r HEAD --name-only  | egrep 'yml$|yaml$')
similarity index 78%
rename from jjb/snaps/snaps.yml
rename to jjb/snaps/snaps-verify-jobs.yml
index 50b7c30..01ea3e4 100644 (file)
             branch: '{stream}'
             gs-pathname: ''
             disabled: false
-        - danube:
-            branch: 'stable/{stream}'
-            gs-pathname: '/{stream}'
-            disabled: false
 
 - job-template:
     name: 'snaps-verify-{stream}'
 
     disabled: '{obj:disabled}'
 
+    concurrent: false
+
     parameters:
         - project-parameter:
             project: '{project}'
             branch: '{branch}'
-        - 'opnfv-build-ubuntu-defaults'
+        - string:
+            name: DEPLOYMENT_HOST_IP
+            default: 192.168.122.2
+            description: 'IP of the deployment node'
+        - string:
+            name: CONTROLLER_IP
+            default: 192.168.122.3
+            description: 'IP of the controller node'
+        - 'intel-virtual10-defaults'
 
     scm:
         - git-scm-gerrit
@@ -60,4 +66,7 @@
 
     builders:
         - shell: |
-            echo "Nothing to verify!"
+            #!/bin/bash
+
+            cd $WORKSPACE/ci
+            ./run_tests.sh $DEPLOYMENT_HOST_IP $CONTROLLER_IP
diff --git a/jjb/storperf/storperf-daily-jobs.yml b/jjb/storperf/storperf-daily-jobs.yml
new file mode 100644 (file)
index 0000000..e849e29
--- /dev/null
@@ -0,0 +1,175 @@
+###################################
+# job configuration for storperf
+###################################
+- project:
+    name: storperf-daily
+
+    project: storperf
+
+#--------------------------------
+# BRANCH ANCHORS
+#--------------------------------
+    master: &master
+        stream: master
+        branch: '{stream}'
+        gs-pathname: ''
+        docker-tag: 'latest'
+#--------------------------------
+# POD, INSTALLER, AND BRANCH MAPPING
+#--------------------------------
+#    Installers using labels
+#            CI PODs
+# This section should only contain the installers
+# that have been switched using labels for slaves
+#--------------------------------
+    pod:
+## fuel CI PODs
+#        - baremetal:
+#            slave-label: fuel-baremetal
+#            installer: fuel
+#            <<: *master
+#        - virtual:
+#            slave-label: fuel-virtual
+#            installer: fuel
+#            <<: *master
+## joid CI PODs
+#        - baremetal:
+#            slave-label: joid-baremetal
+#            installer: joid
+#            <<: *master
+#        - virtual:
+#            slave-label: joid-virtual
+#            installer: joid
+#            <<: *master
+## compass CI PODs
+#        - baremetal:
+#            slave-label: compass-baremetal
+#            installer: compass
+#            <<: *master
+#        - virtual:
+#            slave-label: compass-virtual
+#            installer: compass
+#            <<: *master
+## apex CI PODs
+#        - virtual:
+#            slave-label: apex-virtual-master
+#            installer: apex
+#            <<: *master
+        - baremetal:
+            slave-label: apex-baremetal-master
+            installer: apex
+            <<: *master
+## armband CI PODs
+#        - armband-baremetal:
+#            slave-label: armband-baremetal
+#            installer: fuel
+#            <<: *master
+#        - armband-virtual:
+#            slave-label: armband-virtual
+#            installer: fuel
+#            <<: *master
+## daisy CI PODs
+#        - baremetal:
+#            slave-label: daisy-baremetal
+#            installer: daisy
+#            <<: *master
+#        - virtual:
+#            slave-label: daisy-virtual
+#            installer: daisy
+#            <<: *master
+
+    jobs:
+        - 'storperf-{installer}-{pod}-daily-{stream}'
+
+################################
+# job template
+################################
+- job-template:
+    name: 'storperf-{installer}-{pod}-daily-{stream}'
+
+    concurrent: true
+
+    properties:
+        - logrotate-default
+        - throttle:
+            enabled: true
+            max-per-node: 1
+            option: 'project'
+
+    wrappers:
+        - build-name:
+            name: '$BUILD_NUMBER Scenario: $DEPLOY_SCENARIO'
+        - timeout:
+            timeout: '30'
+            abort: true
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - '{installer}-defaults'
+        - '{slave-label}-defaults'
+        - string:
+            name: DEPLOY_SCENARIO
+            default: 'os-odl_l2-nofeature-ha'
+        - string:
+            name: DOCKER_TAG
+            default: '{docker-tag}'
+            description: 'Tag to pull docker image'
+        - string:
+            name: CLEAN_DOCKER_IMAGES
+            default: 'false'
+            description: 'Remove downloaded docker images (opnfv/storperf*:*)'
+        - string:
+            name: GS_PATHNAME
+            default: '{gs-pathname}'
+            description: "Version directory where the opnfv documents will be stored in gs repository"
+        - string:
+            name: DISK_TYPE
+            default: 'HDD'
+            description: 'The type of hard disk that Cinder uses'
+        - string:
+            name: VOLUME_SIZE
+            default: '2'
+            description: 'Size of Cinder volume (in GB)'
+        - string:
+            name: WORKLOADS
+            default: 'rw'
+            description: 'Workloads to run'
+        - string:
+            name: BLOCK_SIZES
+            default: '16384'
+            description: 'Block sizes for VM I/O operations'
+        - string:
+            name: QUEUE_DEPTHS
+            default: '4'
+            description: 'Number of simultaneous I/O operations to keep active'
+        - string:
+            name: STEADY_STATE_SAMPLES
+            default: '10'
+            description: 'Number of samples to use (1 per minute) to measure steady state'
+        - string:
+            name: TEST_CASE
+            choices:
+                - 'snia_steady_state'
+            description: 'The test case to run'
+
+    scm:
+        - git-scm
+
+    builders:
+        - description-setter:
+            description: "Built on $NODE_NAME"
+        - 'storperf-daily-builder'
+
+########################
+# builder macros
+########################
+- builder:
+    name: storperf-daily-builder
+    builders:
+        - shell: |
+            #!/bin/bash
+
+            cd $WORKSPACE
+            ./ci/daily.sh
diff --git a/jjb/storperf/storperf-verify-jobs.yml b/jjb/storperf/storperf-verify-jobs.yml
new file mode 100644 (file)
index 0000000..f99ceea
--- /dev/null
@@ -0,0 +1,190 @@
+- project:
+    name: storperf-verify
+
+    project: 'storperf'
+
+#--------------------------------
+# branches
+#--------------------------------
+    stream:
+        - master:
+            branch: '{stream}'
+            gs-pathname: ''
+            disabled: false
+            docker-tag: 'latest'
+#--------------------------------
+# patch verification phases
+#--------------------------------
+    phase:
+        - 'unit-test':
+            slave-label: 'opnfv-build-ubuntu'
+        - 'build-x86_64':
+            slave-label: 'opnfv-build-ubuntu'
+        - 'build-aarch64':
+            slave-label: 'opnfv-build-ubuntu-arm'
+#--------------------------------
+# jobs
+#--------------------------------
+    jobs:
+        - 'storperf-verify-{stream}'
+        - 'storperf-verify-{phase}-{stream}'
+#--------------------------------
+# job templates
+#--------------------------------
+- job-template:
+    name: 'storperf-verify-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    project-type: 'multijob'
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - 'opnfv-build-defaults'
+
+    scm:
+        - git-scm-gerrit
+
+    triggers:
+        - gerrit:
+            server-name: 'gerrit.opnfv.org'
+            trigger-on:
+                - patchset-created-event:
+                    exclude-drafts: 'false'
+                    exclude-trivial-rebase: 'false'
+                    exclude-no-code-change: 'false'
+                - draft-published-event
+                - comment-added-contains-event:
+                    comment-contains-value: 'recheck'
+                - comment-added-contains-event:
+                    comment-contains-value: 'reverify'
+            projects:
+              - project-compare-type: 'ANT'
+                project-pattern: '{project}'
+                branches:
+                  - branch-compare-type: 'ANT'
+                    branch-pattern: '**/{branch}'
+
+    builders:
+        - shell: |
+            #!/bin/bash
+
+            # we do nothing here as the main stuff will be done
+            # in phase jobs
+            echo "Triggering phase jobs!"
+        - multijob:
+            name: 'storperf-build-and-unittest'
+            execution-type: PARALLEL
+            projects:
+                - name: 'storperf-verify-unit-test-{stream}'
+                  current-parameters: false
+                  predefined-parameters: |
+                    GERRIT_BRANCH=$GERRIT_BRANCH
+                    GERRIT_REFSPEC=$GERRIT_REFSPEC
+                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
+                  git-revision: true
+                  node-parameters: false
+                  kill-phase-on: FAILURE
+                  abort-all-job: false
+                - name: 'storperf-verify-build-x86_64-{stream}'
+                  current-parameters: false
+                  predefined-parameters: |
+                    GERRIT_BRANCH=$GERRIT_BRANCH
+                    GERRIT_REFSPEC=$GERRIT_REFSPEC
+                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
+                    ARCH=x86_64
+                  git-revision: true
+                  node-parameters: false
+                  kill-phase-on: FAILURE
+                  abort-all-job: false
+                - name: 'storperf-verify-build-aarch64-{stream}'
+                  current-parameters: false
+                  predefined-parameters: |
+                    GERRIT_BRANCH=$GERRIT_BRANCH
+                    GERRIT_REFSPEC=$GERRIT_REFSPEC
+                    GERRIT_CHANGE_NUMBER=$GERRIT_CHANGE_NUMBER
+                    GERRIT_CHANGE_COMMIT_MESSAGE=$GERRIT_CHANGE_COMMIT_MESSAGE
+                    ARCH=aarch64
+                  git-revision: true
+                  node-parameters: false
+                  kill-phase-on: FAILURE
+                  abort-all-job: false
+
+- job-template:
+    name: 'storperf-verify-{phase}-{stream}'
+
+    disabled: '{obj:disabled}'
+
+    wrappers:
+        - ssh-agent-wrapper
+        - build-timeout:
+            timeout: 60
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - '{slave-label}-defaults'
+
+    scm:
+        - git-scm-gerrit
+
+    builders:
+        - 'storperf-verify-{phase}-builders-macro'
+
+    publishers:
+        - 'storperf-verify-{phase}-publishers-macro'
+#--------------------------------
+# builder macros
+#--------------------------------
+- builder:
+    name: 'storperf-verify-unit-test-builders-macro'
+    builders:
+        - shell: |
+            $WORKSPACE/ci/verify.sh
+- builder:
+    name: 'storperf-verify-build-x86_64-builders-macro'
+    builders:
+        - shell: |
+            $WORKSPACE/ci/verify-build.sh
+- builder:
+    name: 'storperf-verify-build-aarch64-builders-macro'
+    builders:
+        - shell: |
+            $WORKSPACE/ci/verify-build.sh
+#--------------------------------
+# publisher macros
+#--------------------------------
+- publisher:
+    name: 'storperf-verify-unit-test-publishers-macro'
+    publishers:
+        - junit:
+            results: nosetests.xml
+        - cobertura:
+            report-file: "coverage.xml"
+            only-stable: "true"
+            health-auto-update: "true"
+            stability-auto-update: "true"
+            zoom-coverage-chart: "true"
+            targets:
+                - files:
+                    healthy: 10
+                    unhealthy: 20
+                    failing: 30
+                - method:
+                    healthy: 50
+                    unhealthy: 40
+                    failing: 30
+        - email-jenkins-admins-on-failure
+- publisher:
+    name: 'storperf-verify-build-x86_64-publishers-macro'
+    publishers:
+        - email-jenkins-admins-on-failure
+- publisher:
+    name: 'storperf-verify-build-aarch64-publishers-macro'
+    publishers:
+        - email-jenkins-admins-on-failure
index 13186a1..307becf 100644 (file)
@@ -4,9 +4,7 @@
     project: '{name}'
 
     jobs:
-        - 'storperf-verify-{stream}'
         - 'storperf-merge-{stream}'
-        - 'storperf-daily-{stream}'
 
     stream:
         - master:
             disabled: false
             docker-tag: 'stable'
 
-- job-template:
-    name: 'storperf-verify-{stream}'
-
-    disabled: '{obj:disabled}'
-
-    node: opnfv-build-ubuntu
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-            description: "Used for overriding the GIT URL coming from Global Jenkins configuration in case if the stuff is done on none-LF HW."
-
-    scm:
-        - git-scm-gerrit
-
-    triggers:
-        - gerrit:
-            server-name: 'gerrit.opnfv.org'
-            trigger-on:
-                - patchset-created-event:
-                    exclude-drafts: 'false'
-                    exclude-trivial-rebase: 'false'
-                    exclude-no-code-change: 'false'
-                - draft-published-event
-                - comment-added-contains-event:
-                    comment-contains-value: 'recheck'
-                - comment-added-contains-event:
-                    comment-contains-value: 'reverify'
-            projects:
-              - project-compare-type: 'ANT'
-                project-pattern: '{project}'
-                branches:
-                  - branch-compare-type: 'ANT'
-                    branch-pattern: '**/{branch}'
-
-    builders:
-        - shell: |
-            $WORKSPACE/ci/verify.sh
-
-    publishers:
-        - junit:
-            results: nosetests.xml
-        - cobertura:
-            report-file: "coverage.xml"
-            only-stable: "true"
-            health-auto-update: "true"
-            stability-auto-update: "true"
-            zoom-coverage-chart: "true"
-            targets:
-                - files:
-                    healthy: 10
-                    unhealthy: 20
-                    failing: 30
-                - method:
-                    healthy: 50
-                    unhealthy: 40
-                    failing: 30
-
 - job-template:
     name: 'storperf-merge-{stream}'
 
                     healthy: 50
                     unhealthy: 40
                     failing: 30
-
-- job-template:
-    name: 'storperf-daily-{stream}'
-
-    # Job template for daily builders
-    #
-    # Required Variables:
-    #     stream:    branch with - in place of / (eg. stable)
-    #     branch:    branch (eg. stable)
-    disabled: '{obj:disabled}'
-
-    parameters:
-        - project-parameter:
-            project: '{project}'
-            branch: '{branch}'
-        - 'intel-pod9-defaults'
-        - string:
-            name: DEPLOY_SCENARIO
-            default: 'os-nosdn-nofeature-noha'
-        - string:
-            name: DOCKER_TAG
-            default: '{docker-tag}'
-            description: 'Tag to pull docker image'
-        - choice:
-            name: DISK_TYPE
-            choices:
-                - 'SSD'
-                - 'HDD'
-            default: 'HDD'
-            description: 'The type of hard disk that Cinder uses'
-        - string:
-            name: AGENT_COUNT
-            description: 'The number of slave agents to start. Defaults to the cinder node count'
-        - string:
-            name: VOLUME_SIZE
-            default: '4'
-            description: 'Size of Cinder volume (in GB)'
-        - string:
-            name: WORKLOADS
-            default: 'wr,rr,rw'
-            description: 'Workloads to run'
-        - string:
-            name: BLOCK_SIZES
-            default: '2048,16384'
-            description: 'Block sizes for VM I/O operations'
-        - string:
-            name: QUEUE_DEPTHS
-            default: '1,4'
-            description: 'Number of simultaneous I/O operations to keep active'
-        - string:
-            name: STEADY_STATE_SAMPLES
-            default: '10'
-            description: 'Number of samples to use (1 per minute) to measure steady state'
-        - string:
-            name: DEADLINE
-            description: 'Maximum run time in minutes if steady state cannot be found. Defaults to 3 times steady state samples'
-        - choice:
-            name: TEST_CASE
-            choices:
-                - 'snia_steady_state'
-            description: 'The test case to run'
-
-    scm:
-        - git-scm
-
-    triggers:
-        - timed: '0 22 * * *'
-
-    builders:
-        - shell: |
-            $WORKSPACE/ci/daily.sh
+        - email-jenkins-admins-on-failure
 
diff --git a/jjb/test-requirements.txt b/jjb/test-requirements.txt
deleted file mode 100644 (file)
index 6b700dc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-jenkins-job-builder
index d5a444d..6f3f51a 100644 (file)
@@ -15,8 +15,8 @@
             project-repo: 'https://git.openstack.org/openstack/bifrost'
             clone-location: '/opt/bifrost'
         - 'opnfv':
-            project-repo: 'https://gerrit.opnfv.org/gerrit/releng'
-            clone-location: '/opt/releng'
+            project-repo: 'https://gerrit.opnfv.org/gerrit/releng-xci'
+            clone-location: '/opt/releng-xci'
 
 #--------------------------------
 # jobs
@@ -83,6 +83,7 @@
     publishers:
         - email:
             recipients: fatih.degirmenci@ericsson.com yroblamo@redhat.com mchandras@suse.de jack.morgan@intel.com zhang.jun3g@zte.com.cn
+        - email-jenkins-admins-on-failure
 #--------------------------------
 # trigger macros
 #--------------------------------
             silent-start: true
             projects:
               - project-compare-type: 'ANT'
-                project-pattern: 'releng'
+                project-pattern: 'releng-xci'
                 branches:
                   - branch-compare-type: 'ANT'
                     branch-pattern: '**/{branch}'
                 file-paths:
                   - compare-type: ANT
-                    pattern: 'prototypes/bifrost/**'
+                    pattern: 'bifrost/**'
             readable-message: true
index 9773cfd..a1892fc 100644 (file)
@@ -1,5 +1,5 @@
 - project:
-    project: 'releng'
+    project: 'releng-xci'
 
     name: 'bifrost-periodic'
 #--------------------------------
@@ -49,7 +49,7 @@
         - 'suse':
             disabled: true
             slave-label: xci-suse-virtual
-            dib-os-release: '42.2'
+            dib-os-release: '42.3'
             dib-os-element: 'opensuse-minimal'
             dib-os-packages: 'vim,less,bridge-utils,iputils,rsyslog,curl'
             extra-dib-elements: 'openssh-server'
index b37da90..4d646a6 100755 (executable)
@@ -38,7 +38,7 @@ if [[ ! "$DISTRO" =~ (xenial|centos7|suse) ]]; then
 fi
 
 # remove previously cloned repos
-sudo /bin/rm -rf /opt/bifrost /opt/openstack-ansible /opt/releng /opt/functest
+sudo /bin/rm -rf /opt/bifrost /opt/openstack-ansible /opt/releng-xci /opt/functest
 
 # Fix up permissions
 fix_ownership
@@ -65,16 +65,16 @@ cd /opt/bifrost && sudo git checkout --quiet $OPENSTACK_BIFROST_VERSION
 echo "xci: using bifrost commit"
 git show --oneline -s --pretty=format:'%h - %s (%cr) <%an>'
 
-sudo git clone --quiet https://gerrit.opnfv.org/gerrit/releng /opt/releng
-cd /opt/releng && sudo git checkout --quiet $OPNFV_RELENG_VERSION
+sudo git clone --quiet https://gerrit.opnfv.org/gerrit/releng-xci /opt/releng-xci
+cd /opt/releng-xci && sudo git checkout --quiet $OPNFV_RELENG_VERSION
 echo "xci: using releng commit"
 git show --oneline -s --pretty=format:'%h - %s (%cr) <%an>'
 
 # source flavor vars
-source "$WORKSPACE/prototypes/xci/config/${XCI_FLAVOR}-vars"
+source "$WORKSPACE/xci/config/${XCI_FLAVOR}-vars"
 
 # combine opnfv and upstream scripts/playbooks
-sudo /bin/cp -rf /opt/releng/prototypes/bifrost/* /opt/bifrost/
+sudo /bin/cp -rf /opt/releng-xci/bifrost/* /opt/bifrost/
 
 # cleanup remnants of previous deployment
 cd /opt/bifrost
index 319f8eb..af51c2b 100644 (file)
@@ -14,8 +14,8 @@
             project-repo: 'https://git.openstack.org/openstack/bifrost'
             clone-location: '$WORKSPACE/bifrost'
         - 'opnfv':
-            project-repo: 'https://gerrit.opnfv.org/gerrit/releng'
-            clone-location: '$WORKSPACE/releng'
+            project-repo: 'https://gerrit.opnfv.org/gerrit/releng-xci'
+            clone-location: '$WORKSPACE/releng-xci'
 #--------------------------------
 # distros
 #--------------------------------
         - 'centos7':
             disabled: false
             dib-os-release: '7'
-            dib-os-element: 'centos7'
+            dib-os-element: 'centos-minimal'
             dib-os-packages: 'vim,less,bridge-utils,iputils,rsyslog,curl'
             extra-dib-elements: 'openssh-server'
         - 'suse':
             disabled: false
-            dib-os-release: '42.2'
+            dib-os-release: '42.3'
             dib-os-element: 'opensuse-minimal'
             dib-os-packages: 'vim,less,bridge-utils,iputils,rsyslog,curl'
             extra-dib-elements: 'openssh-server'
 
     wrappers:
         - fix-workspace-permissions
+        - build-timeout:
+            timeout: 90
 
     publishers:
         - email:
             recipients: fatih.degirmenci@ericsson.com yroblamo@redhat.com mchandras@suse.de jack.morgan@intel.com julienjut@gmail.com
+        - email-jenkins-admins-on-failure
 #--------------------------------
 # trigger macros
 #--------------------------------
             custom-url: '* $JOB_NAME $BIFROST_LOG_URL/index.html'
             projects:
               - project-compare-type: 'ANT'
-                project-pattern: 'releng'
+                project-pattern: 'releng-xci'
                 branches:
                   - branch-compare-type: 'ANT'
                     branch-pattern: '**/{branch}'
                 file-paths:
                   - compare-type: ANT
-                    pattern: 'prototypes/bifrost/**'
+                    pattern: 'bifrost/**'
             readable-message: true
 
 #---------------------------
index b522b89..03d9afc 100755 (executable)
@@ -57,16 +57,17 @@ EOF
 </html>
 EOF
 
+    # Upload landing page
+    echo "Uploading the landing page"
+    gsutil -q cp ${WORKSPACE}/index.html ${BIFROST_GS_URL}/index.html
+    rm -f ${WORKSPACE}/index.html
+
     # Finally, download and upload the entire build log so we can retain
     # as much build information as possible
     echo "Uploading the final console output"
     curl -s -L ${BIFROST_CONSOLE_LOG} > ${WORKSPACE}/build_log.txt
     gsutil -q cp -Z ${WORKSPACE}/build_log.txt ${BIFROST_GS_URL}/build_log.txt
-    rm ${WORKSPACE}/build_log.txt
-
-    # Upload landing page
-    gsutil -q cp ${WORKSPACE}/index.html ${BIFROST_GS_URL}/index.html
-    rm ${WORKSPACE}/index.html
+    rm -f ${WORKSPACE}/build_log.txt
 }
 
 function fix_ownership() {
@@ -83,6 +84,9 @@ function fix_ownership() {
 
 function cleanup_and_upload() {
     original_exit=$?
+    echo "Job exit code: $original_exit"
+    # Turn off errexit
+    set +o errexit
     fix_ownership
     upload_logs
     exit $original_exit
@@ -95,21 +99,21 @@ if [[ ! "$DISTRO" =~ (xenial|centos7|suse) ]]; then
 fi
 
 # remove previously cloned repos
-/bin/rm -rf $WORKSPACE/bifrost $WORKSPACE/releng
+/bin/rm -rf $WORKSPACE/bifrost $WORKSPACE/releng-xci
 
 # Fix up permissions
 fix_ownership
 
 # clone all the repos first and checkout the patch afterwards
 git clone https://git.openstack.org/openstack/bifrost $WORKSPACE/bifrost
-git clone https://gerrit.opnfv.org/gerrit/releng $WORKSPACE/releng
+git clone https://gerrit.opnfv.org/gerrit/releng-xci $WORKSPACE/releng-xci
 
 # checkout the patch
 cd $CLONE_LOCATION
 git fetch $PROJECT_REPO $GERRIT_REFSPEC && sudo git checkout FETCH_HEAD
 
 # combine opnfv and upstream scripts/playbooks
-/bin/cp -rf $WORKSPACE/releng/prototypes/bifrost/* $WORKSPACE/bifrost/
+/bin/cp -rf $WORKSPACE/releng-xci/bifrost/* $WORKSPACE/bifrost/
 
 # cleanup remnants of previous deployment
 cd $WORKSPACE/bifrost
index 722b077..7311baa 100644 (file)
 - project:
-    project: 'releng'
+    name: 'opnfv-osa-periodic'
 
-    name: 'os-periodic'
+    project: 'releng-xci'
 #--------------------------------
-# Branch Anchors
+# branches
 #--------------------------------
-# the versions stated here default to branches which then later
-# on used for checking out the branches, pulling in head of the branch.
-    master: &master
-        stream: master
-        openstack-osa-version: '{stream}'
-        opnfv-releng-version: 'master'
-        gs-pathname: ''
-    ocata: &ocata
-        stream: ocata
-        openstack-osa-version: 'stable/{stream}'
-        opnfv-releng-version: 'master'
-        gs-pathname: '/{stream}'
+    stream:
+        - master:
+            branch: '{stream}'
 #--------------------------------
-#        XCI PODs
-#--------------------------------
-    pod:
-        - virtual:
-            <<: *master
-        - virtual:
-            <<: *ocata
-#--------------------------------
-# Supported Distros
+# distros
 #--------------------------------
     distro:
         - 'xenial':
             disabled: false
-            slave-label: xci-xenial-virtual
-            dib-os-release: 'xenial'
-            dib-os-element: 'ubuntu-minimal'
-            dib-os-packages: 'vlan,vim,less,bridge-utils,sudo,language-pack-en,iputils-ping,rsyslog,curl,python,debootstrap,ifenslave,ifenslave-2.6,lsof,lvm2,tcpdump,nfs-kernel-server,chrony,iptables'
-            extra-dib-elements: 'openssh-server'
         - 'centos7':
             disabled: true
-            slave-label: xci-centos7-virtual
-            dib-os-release: '7'
-            dib-os-element: 'centos7'
-            dib-os-packages: 'vim,less,bridge-utils,iputils,rsyslog,curl'
-            extra-dib-elements: 'openssh-server'
         - 'suse':
             disabled: true
-            slave-label: xci-suse-virtual
-            dib-os-release: '42.2'
-            dib-os-element: 'opensuse-minimal'
-            dib-os-packages: 'vim,less,bridge-utils,iputils,rsyslog,curl'
-            extra-dib-elements: 'openssh-server'
-
+#--------------------------------
+# type
+#--------------------------------
+    type:
+        - virtual
+#--------------------------------
+# phases
+#--------------------------------
+    phase:
+        - 'deploy'
+        - 'healthcheck'
 #--------------------------------
 # jobs
 #--------------------------------
     jobs:
-        - 'osa-deploy-{pod}-{distro}-periodic-{stream}'
-
+        - 'osa-periodic-{distro}-{type}-{stream}'
+        - 'osa-periodic-{phase}-{type}-{stream}'
 #--------------------------------
 # job templates
 #--------------------------------
 - job-template:
-    name: 'osa-deploy-{pod}-{distro}-periodic-{stream}'
+    name: 'osa-periodic-{distro}-{type}-{stream}'
+
+    project-type: multijob
 
     disabled: '{obj:disabled}'
 
     concurrent: false
 
     properties:
+        - logrotate-default
         - build-blocker:
             use-build-blocker: true
             blocking-jobs:
-                - '^xci-os.*'
-                - '^xci-deploy.*'
-                - '^xci-functest.*'
-                - '^bifrost-.*periodic.*'
-                - '^osa-.*periodic.*'
+                - 'xci-verify-.*'
+                - 'bifrost-verify-.*'
+                - 'bifrost-periodic-.*'
+                - 'osa-verify-.*'
+                - 'osa-periodic-.*'
             block-level: 'NODE'
+
+    wrappers:
+        - ssh-agent-wrapper
+        - build-timeout:
+            timeout: 240
+        - fix-workspace-permissions
+
+    scm:
+        - git-scm-osa
+
+    triggers:
+        - pollscm:
+            cron: "@midnight"
+            ignore-post-commit-hooks: True
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - label:
+            name: SLAVE_LABEL
+            default: 'xci-virtual-{distro}'
+
+    builders:
+        - description-setter:
+            description: "Built on $NODE_NAME"
+        - multijob:
+            name: deploy
+            condition: SUCCESSFUL
+            projects:
+                - name: 'osa-periodic-deploy-{type}-{stream}'
+                  current-parameters: true
+                  predefined-parameters: |
+                    DISTRO={distro}
+                    DEPLOY_SCENARIO=os-nosdn-nofeature-noha
+                  git-revision: true
+                  node-parameters: true
+                  kill-phase-on: FAILURE
+                  abort-all-job: true
+        - multijob:
+            name: healthcheck
+            condition: SUCCESSFUL
+            projects:
+                - name: 'osa-periodic-healthcheck-{type}-{stream}'
+                  current-parameters: true
+                  predefined-parameters: |
+                    DISTRO={distro}
+                    DEPLOY_SCENARIO=os-nosdn-nofeature-noha
+                    FUNCTEST_SUITE_NAME=healthcheck
+                  node-parameters: true
+                  kill-phase-on: NEVER
+                  abort-all-job: false
+
+- job-template:
+    name: 'osa-periodic-{phase}-{type}-{stream}'
+
+    disabled: false
+
+    concurrent: true
+
+    properties:
         - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            blocking-jobs:
+                - 'xci-verify-deploy-.*'
+                - 'xci-verify-healthcheck-.*'
+                - 'bifrost-verify-.*'
+                - 'bifrost-periodic-.*'
+                - 'osa-verify-deploy-.*'
+                - 'osa-verify-halthcheck-.*'
+                - 'osa-periodic-deploy-.*'
+                - 'osa-periodic-healthcheck-.*'
+            block-level: 'NODE'
 
     parameters:
         - project-parameter:
             project: '{project}'
-            branch: '{opnfv-releng-version}'
-        - string:
-            name: GIT_BASE
-            default: https://gerrit.opnfv.org/gerrit/$PROJECT
-        - string:
-            name: XCI_FLAVOR
-            default: 'ha'
+            branch: '{branch}'
+        - label:
+            name: SLAVE_LABEL
+            default: 'xci-virtual-{distro}'
         - string:
             name: OPENSTACK_OSA_VERSION
-            default: '{openstack-osa-version}'
-        - string:
-            name: OPNFV_RELENG_VERSION
-            default: '{opnfv-releng-version}'
+            default: 'master'
         - string:
             name: DISTRO
-            default: '{distro}'
+            default: 'xenial'
         - string:
-            name: DIB_OS_RELEASE
-            default: '{dib-os-release}'
+            name: DEPLOY_SCENARIO
+            default: 'os-nosdn-nofeature-noha'
         - string:
-            name: DIB_OS_ELEMENT
-            default: '{dib-os-element}'
+            name: XCI_FLAVOR
+            default: 'mini'
         - string:
-            name: DIB_OS_PACKAGES
-            default: '{dib-os-packages}'
+            name: XCI_LOOP
+            default: 'periodic'
         - string:
-            name: EXTRA_DIB_ELEMENTS
-            default: '{extra-dib-elements}'
+            name: OPNFV_RELENG_DEV_PATH
+            default: $WORKSPACE/releng-xci
         - string:
-            name: CLEAN_DIB_IMAGES
-            default: 'true'
-        - label:
-            name: SLAVE_LABEL
-            default: '{slave-label}'
+            name: FUNCTEST_SUITE_NAME
+            default: 'healthcheck'
         - string:
             name: ANSIBLE_VERBOSITY
-            default: ''
+            default: '-vvvv'
         - string:
-            name: XCI_LOOP
-            default: 'periodic'
-
-    wrappers:
-        - fix-workspace-permissions
+            name: FORCE_MASTER
+            default: 'true'
+        - string:
+            name: GIT_BASE
+            default: https://gerrit.opnfv.org/gerrit/$PROJECT
 
     scm:
-        - git-scm
+        - git-scm-osa
 
-    # trigger is disabled until we know which jobs we will have
-    # and adjust stuff accordingly
-    triggers:
-        - timed: ''  # '@midnight'
+    wrappers:
+        - ssh-agent-wrapper
+        - build-timeout:
+            timeout: 240
+        - fix-workspace-permissions
 
     builders:
         - description-setter:
-            description: "Built on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
-        - 'osa-deploy-builder'
+            description: "Built on $NODE_NAME"
+        - 'osa-periodic-{phase}-macro'
 
-#---------------------------
+#--------------------------------
 # builder macros
-#---------------------------
+#--------------------------------
 - builder:
-    name: osa-deploy-builder
+    name: 'osa-periodic-deploy-macro'
     builders:
-        - shell:
-            !include-raw: ./xci-deploy.sh
+        - shell: |
+            #!/bin/bash
+
+            # here we will
+            # - clone releng-xci repo as the jobs are running against openstack gerrit
+            #   and we need to clone releng-xci ourselves to $OPNFV_RELENG_DEV_PATH
+            # - run sources-branch-updater.sh from osa to update/pin the role versions
+            #   at the time this job gets triggered against osa master in case if the
+            #   deployment succeeds and we decide to bump version used by xci
+            # - copy generated role versions into $OPNFV_RELENG_DEV_PATH/xci/file
+            # - start the deployment by executing xci-deploy.sh as usual
+            #
+            # we might also need to pin versions of openstack services as well.
+
+            echo "Hello World!"
+
+- builder:
+    name: 'osa-periodic-healthcheck-macro'
+    builders:
+        - shell: |
+            #!/bin/bash
+
+            echo "Hello World!"
+#--------------------------------
+# scm macro
+#--------------------------------
+- scm:
+    name: git-scm-osa
+    scm:
+        - git:
+            url: https://review.openstack.org/p/openstack/openstack-ansible.git
+            branches:
+                - master
+            timeout: 15
index 64e13d3..0835e67 100644 (file)
@@ -6,7 +6,7 @@
 # are checked out based on what is configured.
 #--------------------------------
 - project:
-    project: 'releng'
+    project: 'releng-xci'
 
     name: 'xci-daily'
 #--------------------------------
         stream: master
         opnfv-releng-version: master
         gs-pathname: ''
-    ocata: &ocata
-        stream: ocata
-        opnfv-releng-version: master
-        gs-pathname: '/{stream}'
 #--------------------------------
 # Scenarios
 #--------------------------------
         - 'os-nosdn-nofeature-noha':
             auto-trigger-name: 'daily-trigger-disabled'
             xci-flavor: 'noha'
+        - 'os-odl-sfc-ha':
+            auto-trigger-name: 'daily-trigger-disabled'
+            xci-flavor: 'ha'
+        - 'os-odl-sfc-noha':
+            auto-trigger-name: 'daily-trigger-disabled'
+            xci-flavor: 'noha'
 #--------------------------------
 # XCI PODs
 #--------------------------------
     pod:
         - virtual:
             <<: *master
-        - virtual:
-            <<: *ocata
 #--------------------------------
 # Supported Distros
 #--------------------------------
@@ -59,7 +59,7 @@
         - 'suse':
             disabled: true
             slave-label: xci-suse-virtual
-            dib-os-release: '42.2'
+            dib-os-release: '42.3'
             dib-os-element: 'opensuse-minimal'
             dib-os-packages: 'vim,less,bridge-utils,iputils,rsyslog,curl'
             extra-dib-elements: 'openssh-server'
     publishers:
         - email:
             recipients: fatih.degirmenci@ericsson.com yroblamo@redhat.com mchandras@suse.de jack.morgan@intel.com julienjut@gmail.com
+        - email-jenkins-admins-on-failure
 
 - job-template:
     name: 'xci-{phase}-{pod}-{distro}-daily-{stream}'
         - string:
             name: XCI_LOOP
             default: 'daily'
-
+        - string:
+            name: INSTALLER_TYPE
+            default: 'osa'
+        - string:
+            name: FUNCTEST_SUITE_NAME
+            default: 'daily'
+            description: "Daily suite name to run"
     builders:
         - description-setter:
             description: "Built on $NODE_NAME - Scenario: $DEPLOY_SCENARIO"
 - builder:
     name: xci-functest-builder
     builders:
-        - shell:
-            !include-raw: ./xci-functest.sh
+        - shell: |
+            #!/bin/bash
+
+            echo "Hello World!"
+
+# this will be enabled once the xci is prepared
+#- builder:
+#    name: xci-functest-builder
+#    builders:
+#        - shell:
+#            !include-raw:
+#                - ../../utils/fetch_os_creds.sh
+#                - ../functest/functest-alpine.sh
index 8ad6378..211d282 100755 (executable)
@@ -11,7 +11,7 @@ set -o errexit
 set -o nounset
 set -o pipefail
 
-cd $WORKSPACE/prototypes/xci
+cd $WORKSPACE/xci
 
 # for daily jobs, we want to use working versions
 # for periodic jobs, we will use whatever is set in the job, probably master
@@ -53,7 +53,7 @@ if [[ "$XCI_LOOP" == "periodic" && "$OPENSTACK_OSA_VERSION" == "master" ]]; then
 fi
 
 # proceed with the deployment
-cd $WORKSPACE/prototypes/xci
+cd $WORKSPACE/xci
 ./xci-deploy.sh
 
 if [[ "$JOB_NAME" =~ "periodic" && "$OPENSTACK_OSA_VERSION" == "master" ]]; then
diff --git a/jjb/xci/xci-functest.sh b/jjb/xci/xci-functest.sh
deleted file mode 100755 (executable)
index 0f58dfe..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-echo "Functional testing with functest"
diff --git a/jjb/xci/xci-verify-jobs.yml b/jjb/xci/xci-verify-jobs.yml
new file mode 100644 (file)
index 0000000..2cdecb2
--- /dev/null
@@ -0,0 +1,236 @@
+- project:
+    name: 'opnfv-xci-verify'
+
+    project: releng-xci
+#--------------------------------
+# branches
+#--------------------------------
+    stream:
+        - master:
+            branch: '{stream}'
+#--------------------------------
+# distros
+#--------------------------------
+    distro:
+        - 'xenial':
+            disabled: false
+        - 'centos7':
+            disabled: true
+        - 'suse':
+            disabled: true
+#--------------------------------
+# type
+#--------------------------------
+    type:
+        - virtual
+#--------------------------------
+# patch verification phases
+#--------------------------------
+    phase:
+        - 'deploy'
+        - 'healthcheck'
+#--------------------------------
+# jobs
+#--------------------------------
+    jobs:
+        - 'xci-verify-{distro}-{type}-{stream}'
+        - 'xci-verify-{phase}-{type}-{stream}'
+#--------------------------------
+# job templates
+#--------------------------------
+- job-template:
+    name: 'xci-verify-{distro}-{type}-{stream}'
+
+    project-type: multijob
+
+    disabled: '{obj:disabled}'
+
+    concurrent: true
+
+    properties:
+        - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            blocking-jobs:
+                - 'xci-verify-.*'
+                - 'bifrost-verify-.*'
+                - 'bifrost-periodic-.*'
+                - 'osa-verify-.*'
+                - 'osa-periodic-.*'
+            block-level: 'NODE'
+
+    wrappers:
+        - ssh-agent-wrapper
+        - build-timeout:
+            timeout: 240
+        - fix-workspace-permissions
+
+    scm:
+        - git-scm-gerrit
+
+    triggers:
+        - gerrit:
+            server-name: 'gerrit.opnfv.org'
+            trigger-on:
+                - patchset-created-event:
+                    exclude-drafts: 'false'
+                    exclude-trivial-rebase: 'false'
+                    exclude-no-code-change: 'true'
+                - draft-published-event
+                - comment-added-contains-event:
+                    comment-contains-value: 'recheck'
+                - comment-added-contains-event:
+                    comment-contains-value: 'reverify'
+            projects:
+              - project-compare-type: 'ANT'
+                project-pattern: '{project}'
+                branches:
+                  - branch-compare-type: 'ANT'
+                    branch-pattern: '**/{branch}'
+                disable-strict-forbidden-file-verification: 'false'
+                forbidden-file-paths:
+                  - compare-type: ANT
+                    pattern: 'bifrost/**'
+                  - compare-type: ANT
+                    pattern: 'prototypes/**'
+                  - compare-type: ANT
+                    pattern: 'upstream/**'
+                  - compare-type: ANT
+                    pattern: '**/README.rst'
+            readable-message: true
+
+    parameters:
+        - project-parameter:
+            project: '{project}'
+            branch: '{branch}'
+        - label:
+            name: SLAVE_LABEL
+            default: 'xci-virtual-{distro}'
+        - string:
+            name: GIT_BASE
+            default: https://gerrit.opnfv.org/gerrit/$PROJECT
+            description: 'Git URL to use on this Jenkins Slave'
+
+    builders:
+        - description-setter:
+            description: "Built on $NODE_NAME"
+        - multijob:
+            name: deploy
+            condition: SUCCESSFUL
+            projects:
+                - name: 'xci-verify-deploy-{type}-{stream}'
+                  current-parameters: true
+                  predefined-parameters: |
+                    DISTRO={distro}
+                    DEPLOY_SCENARIO=os-nosdn-nofeature-noha
+                  node-parameters: true
+                  kill-phase-on: FAILURE
+                  abort-all-job: true
+        - multijob:
+            name: healthcheck
+            condition: SUCCESSFUL
+            projects:
+                - name: 'xci-verify-healthcheck-{type}-{stream}'
+                  current-parameters: true
+                  predefined-parameters: |
+                    DISTRO={distro}
+                    DEPLOY_SCENARIO=os-nosdn-nofeature-noha
+                    FUNCTEST_SUITE_NAME=healthcheck
+                  node-parameters: true
+                  kill-phase-on: NEVER
+                  abort-all-job: true
+
+- job-template:
+    name: 'xci-verify-{phase}-{type}-{stream}'
+
+    disabled: false
+
+    concurrent: true
+
+    properties:
+        - logrotate-default
+        - build-blocker:
+            use-build-blocker: true
+            blocking-jobs:
+                - 'xci-verify-deploy-.*'
+                - 'xci-verify-healthcheck-.*'
+                - 'bifrost-verify-.*'
+                - 'bifrost-periodic-.*'
+                - 'osa-verify-.*'
+                - 'osa-periodic-.*'
+            block-level: 'NODE'
+
+    parameters:
+        - string:
+            name: DISTRO
+            default: 'xenial'
+        - string:
+            name: DEPLOY_SCENARIO
+            default: 'os-nosdn-nofeature-noha'
+        - string:
+            name: FUNCTEST_SUITE_NAME
+            default: 'healthcheck'
+        - string:
+            name: XCI_FLAVOR
+            default: 'mini'
+        - string:
+            name: OPNFV_RELENG_DEV_PATH
+            default: $WORKSPACE/
+        - string:
+            name: ANSIBLE_VERBOSITY
+            default: '-vvvv'
+        - string:
+            name: INSTALLER_TYPE
+            default: 'osa'
+        - string:
+            name: GIT_BASE
+            default: https://gerrit.opnfv.org/gerrit/$PROJECT
+            description: 'Git URL to use on this Jenkins Slave'
+
+    wrappers:
+        - ssh-agent-wrapper
+        - build-timeout:
+            timeout: 240
+        - fix-workspace-permissions
+
+    scm:
+        - git-scm-gerrit
+
+    builders:
+        - description-setter:
+            description: "Built on $NODE_NAME"
+        - 'xci-verify-{phase}-macro'
+
+#--------------------------------
+# builder macros
+#--------------------------------
+- builder:
+    name: 'xci-verify-deploy-macro'
+    builders:
+        - shell: |
+            #!/bin/bash
+
+            # for some reason, the PATH is not set correctly
+            # setting PATH for ansible stuff
+            export PATH=/home/jenkins/.local/bin:$PATH
+
+            cd $WORKSPACE/xci
+            ./xci-deploy.sh
+
+
+- builder:
+    name: 'xci-verify-healthcheck-macro'
+    builders:
+        - shell: |
+            #!/bin/bash
+
+            echo "Hello World!"
+
+# this will be enabled once the xci is prepared
+#- builder:
+#    name: 'xci-verify-healthcheck-macro'
+#    builders:
+#        - shell:
+#            !include-raw: ../../utils/fetch_os_creds.sh
+#        - shell:
+#            !include-raw: ../functest/functest-alpine.sh
index ff1d47e..5d38a0b 100644 (file)
 # that have been switched using labels for slaves
 #--------------------------------
     pod:
+# apex CI PODs
+        - virtual:
+            slave-label: apex-virtual-master
+            installer: apex
+            auto-trigger-name: 'daily-trigger-disabled'
+            <<: *master
+        - baremetal:
+            slave-label: apex-baremetal-master
+            installer: apex
+            auto-trigger-name: 'daily-trigger-disabled'
+            <<: *master
+        - virtual:
+            slave-label: apex-virtual-danube
+            installer: apex
+            auto-trigger-name: 'daily-trigger-disabled'
+            <<: *danube
+        - baremetal:
+            slave-label: apex-baremetal-danube
+            installer: apex
+            auto-trigger-name: 'daily-trigger-disabled'
+            <<: *danube
 # fuel CI PODs
         - baremetal:
             slave-label: fuel-baremetal
             installer: joid
             auto-trigger-name: 'daily-trigger-disabled'
             <<: *danube
-
 # compass CI PODs
         - baremetal:
             slave-label: compass-baremetal
             auto-trigger-name: 'daily-trigger-disabled'
             <<: *danube
 #--------------------------------
-#    Installers not using labels
-#            CI PODs
-# This section should only contain the installers
-# that have not been switched using labels for slaves
-#--------------------------------
-        - lf-pod1:
-            slave-label: '{pod}'
-            installer: apex
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *master
-        - lf-pod1:
-            slave-label: '{pod}'
-            installer: apex
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *danube
-#--------------------------------
 #        None-CI PODs
 #--------------------------------
         - orange-pod1:
             installer: fuel
             auto-trigger-name: 'daily-trigger-disabled'
             <<: *danube
-        - arm-pod2:
-            slave-label: '{pod}'
-            installer: fuel
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *master
-        - arm-pod2:
-            slave-label: '{pod}'
-            installer: fuel
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *danube
-        - arm-pod3:
-            slave-label: '{pod}'
-            installer: fuel
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *master
-        - arm-pod3:
-            slave-label: '{pod}'
-            installer: fuel
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *danube
-        - arm-virtual1:
-            slave-label: '{pod}'
-            installer: fuel
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *master
-        - arm-virtual1:
-            slave-label: '{pod}'
-            installer: fuel
-            auto-trigger-name: 'daily-trigger-disabled'
-            <<: *danube
         - orange-pod2:
             slave-label: '{pod}'
             installer: joid
             installer: compass
             auto-trigger-name: 'daily-trigger-disabled'
             <<: *master
+        - flex-pod1:
+            slave-label: '{pod}'
+            installer: apex
+            auto-trigger-name: 'daily-trigger-disabled'
+            <<: *master
 #--------------------------------
     testsuite:
         - 'daily'
         - description-setter:
             description: "POD: $NODE_NAME"
         - 'yardstick-cleanup'
-        #- 'yardstick-fetch-os-creds'
+        - 'yardstick-fetch-os-creds'
+        - 'yardstick-fetch-k8s-conf'
         - 'yardstick-{testsuite}'
         - 'yardstick-store-results'
 
     publishers:
         - email:
             recipients: jean.gaoliang@huawei.com limingjiang@huawei.com ross.b.brattain@intel.com
+        - email-jenkins-admins-on-failure
 
 ########################
 # builder macros
         - shell:
             !include-raw: ../../utils/fetch_os_creds.sh
 
+- builder:
+    name: yardstick-fetch-k8s-conf
+    builders:
+        - shell:
+            !include-raw: ./yardstick-get-k8s-conf.sh
+
 - builder:
     name: yardstick-store-results
     builders:
 # parameter macros
 ########################
 - parameter:
-    name: 'yardstick-params-fuel-baremetal'
+    name: 'yardstick-params-apex-virtual-master'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
 - parameter:
-    name: 'yardstick-params-fuel-virtual'
+    name: 'yardstick-params-apex-baremetal-master'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
 - parameter:
-    name: 'yardstick-params-armband-baremetal'
+    name: 'yardstick-params-apex-virtual-danube'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
 - parameter:
-    name: 'yardstick-params-armband-virtual'
+    name: 'yardstick-params-apex-baremetal-danube'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
 - parameter:
-    name: 'yardstick-params-arm-virtual1'
+    name: 'yardstick-params-fuel-baremetal'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
 - parameter:
-    name: 'yardstick-params-joid-baremetal'
+    name: 'yardstick-params-fuel-virtual'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
 - parameter:
-    name: 'yardstick-params-joid-virtual'
+    name: 'yardstick-params-armband-baremetal'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
 - parameter:
-    name: 'yardstick-params-intel-pod8'
+    name: 'yardstick-params-armband-virtual'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
 - parameter:
-    name: 'yardstick-params-lf-pod1'
+    name: 'yardstick-params-joid-baremetal'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
-
 - parameter:
-    name: 'yardstick-params-lf-pod2'
+    name: 'yardstick-params-joid-virtual'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
-
 - parameter:
-    name: 'yardstick-params-compass-baremetal'
+    name: 'yardstick-params-intel-pod8'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
 - parameter:
-    name: 'yardstick-params-zte-pod1'
+    name: 'yardstick-params-compass-baremetal'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             default: '-i 104.197.68.199:8086'
             description: 'Arguments to use in order to choose the backend DB'
-
 - parameter:
-    name: 'yardstick-params-zte-pod2'
+    name: 'yardstick-params-zte-pod1'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'yardstick-params-zte-pod3'
+    name: 'yardstick-params-zte-pod2'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'yardstick-params-orange-pod1'
+    name: 'yardstick-params-zte-pod3'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'yardstick-params-orange-pod2'
+    name: 'yardstick-params-orange-pod1'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'yardstick-params-arm-pod2'
+    name: 'yardstick-params-orange-pod2'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'yardstick-params-arm-pod3'
+    name: 'yardstick-params-virtual'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'yardstick-params-virtual'
+    name: 'yardstick-params-compass-virtual'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'yardstick-params-compass-virtual'
+    name: 'yardstick-params-huawei-pod3'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'yardstick-params-huawei-pod3'
+    name: 'yardstick-params-huawei-pod4'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
             description: 'Arguments to use in order to choose the backend DB'
 
 - parameter:
-    name: 'yardstick-params-huawei-pod4'
+    name: 'yardstick-params-flex-pod1'
     parameters:
         - string:
             name: YARDSTICK_DB_BACKEND
 - trigger:
     name: 'yardstick-daily-huawei-pod4-trigger'
     triggers:
-        - timed: '0 1 * * *'
+        - timed: ''
index 1c2abad..aaefba2 100755 (executable)
@@ -2,9 +2,10 @@
 set -e
 [[ $CI_DEBUG == true ]] && redirect="/dev/stdout" || redirect="/dev/null"
 
-# labconfig is used only for joid
-labconfig=""
+rc_file_vol=""
+cacert_file_vol=""
 sshkey=""
+
 if [[ ${INSTALLER_TYPE} == 'apex' ]]; then
     instack_mac=$(sudo virsh domiflist undercloud | grep default | \
                   grep -Eo "[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+")
@@ -15,12 +16,24 @@ if [[ ${INSTALLER_TYPE} == 'apex' ]]; then
         sudo iptables -D FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
         sudo iptables -D FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable
     fi
-elif [[ ${INSTALLER_TYPE} == 'joid' ]]; then
-    # If production lab then creds may be retrieved dynamically
-    # creds are on the jumphost, always in the same folder
-    labconfig="-v $LAB_CONFIG/admin-openrc:/etc/yardstick/openstack.creds"
-    # If dev lab, credentials may not be the default ones, just provide a path to put them into docker
-    # replace the default one by the customized one provided by jenkins config
+fi
+
+if [[ ${INSTALLER_TYPE} == 'joid' ]]; then
+    if [[ "${DEPLOY_SCENARIO:0:2}" == "k8" ]];then
+        rc_file_vol="-v /home/ubuntu/config:/etc/yardstick/admin.conf"
+    else
+        # If production lab then creds may be retrieved dynamically
+        # creds are on the jumphost, always in the same folder
+        rc_file_vol="-v $LAB_CONFIG/admin-openrc:/etc/yardstick/openstack.creds"
+        # If dev lab, credentials may not be the default ones, just provide a path to put them into docker
+        # replace the default one by the customized one provided by jenkins config
+    fi
+elif [[ ${INSTALLER_TYPE} == 'compass' && ${BRANCH} == 'master' ]]; then
+    cacert_file_vol="-v ${HOME}/os_cacert:/etc/yardstick/os_cacert"
+    echo "export OS_CACERT=/etc/yardstick/os_cacert" >> ${HOME}/opnfv-openrc.sh
+    rc_file_vol="-v ${HOME}/opnfv-openrc.sh:/etc/yardstick/openstack.creds"
+else
+    rc_file_vol="-v ${HOME}/opnfv-openrc.sh:/etc/yardstick/openstack.creds"
 fi
 
 # Set iptables rule to allow forwarding return traffic for container
@@ -46,8 +59,14 @@ sudo rm -rf ${dir_result}/*
 map_log_dir="-v ${dir_result}:/tmp/yardstick"
 
 # Run docker
-cmd="sudo docker run ${opts} ${envs} ${labconfig} ${map_log_dir} ${sshkey} opnfv/yardstick:${DOCKER_TAG} \
+if [[ ${INSTALLER_TYPE} == "joid" && "${DEPLOY_SCENARIO:0:2}" == "k8" ]];then
+    juju ssh kubernetes-master/0 sudo apt-get install -y docker.io
+    cmd="juju ssh kubernetes-master/0 sudo docker run ${opts} ${envs} ${rc_file_vol} ${cacert_file_vol} ${map_log_dir} ${sshkey} opnfv/yardstick:${DOCKER_TAG} exec_tests.sh ${YARDSTICK_DB_BACKEND} ${YARDSTICK_SCENARIO_SUITE_NAME}"
+else
+    cmd="sudo docker run ${opts} ${envs} ${rc_file_vol} ${cacert_file_vol} ${map_log_dir} ${sshkey} opnfv/yardstick:${DOCKER_TAG} \
     exec_tests.sh ${YARDSTICK_DB_BACKEND} ${YARDSTICK_SCENARIO_SUITE_NAME}"
+fi
+
 echo "Yardstick: Running docker cmd: ${cmd}"
 ${cmd}
 
diff --git a/jjb/yardstick/yardstick-get-k8s-conf.sh b/jjb/yardstick/yardstick-get-k8s-conf.sh
new file mode 100755 (executable)
index 0000000..e93367f
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+
+dest_path="$HOME/admin.conf"
+
+if [[ "${DEPLOY_SCENARIO:0:2}" == "k8" ]];then
+    juju scp kubernetes-master/0:config "${dest_path}"
+fi
diff --git a/modules/setup.cfg b/modules/setup.cfg
new file mode 100644 (file)
index 0000000..dbe5a37
--- /dev/null
@@ -0,0 +1,7 @@
+[metadata]
+name = opnfv
+version = 5
+home-page = https://wiki.opnfv.org/display/releng/Releng
+
+[files]
+packages = opnfv
index 0dd635f..a1e9b3b 100644 (file)
@@ -1,25 +1,22 @@
-##############################################################################
+#!/usr/bin/env python
+
+# Copyright (c) 2017 Orange and others.
+#
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Apache License, Version 2.0
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-
 
-from setuptools import setup, find_packages
+import setuptools
 
+# In python < 2.7.4, a lazy loading of package `pbr` will break
+# setuptools if some other modules registered functions in `atexit`.
+# solution from: http://bugs.python.org/issue15881#msg170215
+try:
+    import multiprocessing  # noqa
+except ImportError:
+    pass
 
-setup(
-    name="opnfv",
-    version="danube",
-    packages=find_packages(),
-    include_package_data=True,
-    package_data={
-    },
-    url="https://www.opnfv.org",
-    install_requires=["paramiko>=2.0",
-                      "mock>=2.0",
-                      "requests!=2.12.2,>=2.10.0"],
-    test_requires=["nose",
-                   "coverage>=4.0"]
-)
+setuptools.setup(
+    setup_requires=['pbr>=1.8'],
+    pbr=True)
diff --git a/modules/tox.ini b/modules/tox.ini
new file mode 100644 (file)
index 0000000..835cb6b
--- /dev/null
@@ -0,0 +1,28 @@
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py27
+skipsdist = True
+
+[testenv]
+usedevelop = True
+setenv=
+  HOME = {envtmpdir}
+  PYTHONPATH = {toxinidir}
+
+[testenv:modules]
+deps=
+  -rrequirements.txt
+  -rtest-requirements.txt
+commands =
+  nosetests \
+  --with-xunit \
+  --xunit-file=nosetests.xml \
+  --cover-package=opnfv \
+  --with-coverage \
+  --cover-xml \
+  --cover-html \
+  tests/unit
diff --git a/prototypes/bifrost/README.md b/prototypes/bifrost/README.md
deleted file mode 100644 (file)
index dc1417a..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-=====================
-How to deploy bifrost
-=====================
-The scripts and playbooks defined on this repo, need to be combined with proper `Bifrost <http://git.openstack.org/cgit/openstack/bifrost>`_ code.
-
-Please follow that steps:
-
-1. Clone bifrost::
-
-    sudo git clone https://git.openstack.org/openstack/bifrost /opt/bifrost
-
-2. Clone releng::
-
-    sudo git clone https://gerrit.opnfv.org/gerrit/releng /opt/releng
-
-3. Clone infracloud::
-
-    sudo git clone https://git.openstack.org/openstack-infra/puppet-infracloud /opt/puppet-infracloud
-
-4. Combine releng scripts and playbooks with bifrost::
-
-    sudo cp -R /opt/releng/prototypes/bifrost/* /opt/bifrost/
-
-5. Copy /opt/puppet-infracloud/templates/bifrost/create_bridge.py.erb to /opt/puppet-infracloud/files/elements/infra-cloud-bridge/static/opt/create_bridge.py,
-   and replace tag <%= @bridge_name -%> with br_opnfv
-
-6. If you are on a RHEL/CentOS box, ensure that selinux is disabled
-
-7. Run destroy script if you need to cleanup previous environment::
-
-    cd /opt/bifrost
-    sudo ./scripts/destroy-env.sh
-
-8. Run deployment script to spin up 3 vms with bifrost: xcimaster, controller and compute::
-
-    cd /opt/bifrost
-    sudo ./scripts/test-bifrost-deployment.sh
-
-It is likely that the script will show some errors due to timeout. Please ignore the errors, and wait until the vms are completely bootstrapped. To verify it you can check with ironic::
-
-    cd /opt/bifrost
-    source env-vars
-    ironic node-list
-
-And wait until all the vms are in **active** Provisioning State.
-
-9. Check the IPs assigned to each of the VMS. You can check it by looking at inventory:
-
-    cat /tmp/baremetal.csv
-
-10. You can enter into the vms with devuser login/pass:
-
-    ssh devuser@192.168.122.2
diff --git a/prototypes/bifrost/playbooks/opnfv-virtual.yaml b/prototypes/bifrost/playbooks/opnfv-virtual.yaml
deleted file mode 100644 (file)
index 94de628..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 RedHat and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
----
-- hosts: localhost
-  connection: local
-  name: "Setting pre-test conditions"
-  become: yes
-  ignore_errors: yes
-  tasks:
-  - name: Remove pre-existing leases file
-    file: path=/var/lib/misc/dnsmasq.leases state=absent
-- hosts: localhost
-  connection: local
-  name: "Executes install, enrollment, and testing in one playbook"
-  become: no
-  gather_facts: yes
-  pre_tasks:
-    - name: "Override the ipv4_gateway setting"
-      set_fact:
-         ipv4_gateway: "192.168.122.1"
-  roles:
-    - { role: bifrost-prep-for-install, when: skip_install is not defined }
-  environment:
-    http_proxy: "{{ lookup('env','http_proxy') }}"
-    https_proxy: "{{ lookup('env','https_proxy') }}"
-- hosts: localhost
-  connection: local
-  name: "Executes install, enrollment, and testing in one playbook"
-  become: yes
-  gather_facts: yes
-  roles:
-    - role: bifrost-keystone-install
-    - role: bifrost-ironic-install
-      cleaning: false
-      testing: true
-    # NOTE(TheJulia): While the next step creates a ramdisk, some elements
-    # do not support ramdisk-image-create as they invoke steps to cleanup
-    # the ramdisk which causes ramdisk-image-create to believe it failed.
-    - role: bifrost-create-dib-image
-      dib_imagename: "{{ http_boot_folder }}/ipa"
-      build_ramdisk: false
-      dib_os_element: "{{ ipa_dib_os_element|default('debian') }}"
-      dib_os_release: "jessie"
-      dib_elements: "ironic-agent {{ ipa_extra_dib_elements | default('') }}"
-      when: create_ipa_image | bool == true
-    - role: bifrost-create-dib-image
-      dib_imagetype: "qcow2"
-      dib_imagename: "{{deploy_image}}"
-      dib_os_element: "{{ lookup('env','DIB_OS_ELEMENT') }}"
-      dib_os_release: "{{ lookup('env', 'DIB_OS_RELEASE') }}"
-      extra_dib_elements: "{{ lookup('env', 'EXTRA_DIB_ELEMENTS') | default('') }}"
-      dib_elements: "vm enable-serial-console simple-init devuser growroot {{ extra_dib_elements }}"
-      dib_packages: "{{ lookup('env', 'DIB_OS_PACKAGES') }}"
-      when: create_image_via_dib | bool == true and transform_boot_image | bool == false
-    - role: bifrost-keystone-client-config
-      user: "{{ ansible_env.SUDO_USER }}"
-      clouds:
-        bifrost:
-          config_username: "{{ ironic.keystone.default_username }}"
-          config_password: "{{ ironic.keystone.default_password }}"
-          config_project_name: "baremetal"
-          config_region_name: "{{ keystone.bootstrap.region_name }}"
-          config_auth_url: "{{ keystone.bootstrap.public_url }}"
-  environment:
-    http_proxy: "{{ lookup('env','http_proxy') }}"
-    https_proxy: "{{ lookup('env','https_proxy') }}"
-- hosts: baremetal
-  name: "Enroll node with Ironic"
-  become: no
-  connection: local
-  roles:
-    - role: ironic-enroll-dynamic
-    - { role: ironic-inspect-node, when: inspect_nodes | default('false') | bool == true }
-- hosts: baremetal
-  name: "Create configuration drive files and deploy machines"
-  vars:
-    multinode_testing: "{{ inventory_dhcp | bool == true }}"
-  become: no
-  connection: local
-  roles:
-    - role: bifrost-configdrives-dynamic
-    - role: bifrost-deploy-nodes-dynamic
-- hosts: baremetal
-  name: "Deploy machines."
-  become: no
-  connection: local
-  serial: 1
-  roles:
-    - role: bifrost-prepare-for-test-dynamic
diff --git a/prototypes/bifrost/scripts/bifrost-provision.sh b/prototypes/bifrost/scripts/bifrost-provision.sh
deleted file mode 100755 (executable)
index 2b90215..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -eux
-set -o pipefail
-
-export PYTHONUNBUFFERED=1
-SCRIPT_HOME="$(cd "$(dirname "$0")" && pwd)"
-BIFROST_HOME=$SCRIPT_HOME/..
-ANSIBLE_INSTALL_ROOT=${ANSIBLE_INSTALL_ROOT:-/opt/stack}
-ANSIBLE_VERBOSITY=${ANSIBLE_VERBOSITY-"-vvvv"}
-ENABLE_VENV="false"
-USE_DHCP="false"
-USE_VENV="false"
-BUILD_IMAGE=true
-PROVISION_WAIT_TIMEOUT=${PROVISION_WAIT_TIMEOUT:-3600}
-
-# Ensure the right inventory files is used based on branch
-CURRENT_BIFROST_BRANCH=$(git rev-parse --abbrev-ref HEAD)
-if [ $CURRENT_BIFROST_BRANCH = "master" ]; then
-    BAREMETAL_DATA_FILE=${BAREMETAL_DATA_FILE:-'/tmp/baremetal.json'}
-    INVENTORY_FILE_FORMAT="baremetal_json_file"
-else
-    BAREMETAL_DATA_FILE=${BAREMETAL_DATA_FILE:-'/tmp/baremetal.csv'}
-    INVENTORY_FILE_FORMAT="baremetal_csv_file"
-fi
-export BIFROST_INVENTORY_SOURCE=$BAREMETAL_DATA_FILE
-
-# Default settings for VMs
-export TEST_VM_NUM_NODES=${TEST_VM_NUM_NODES:-3}
-export TEST_VM_NODE_NAMES=${TEST_VM_NODE_NAMES:-"opnfv controller00 compute00"}
-export VM_DOMAIN_TYPE=${VM_DOMAIN_TYPE:-kvm}
-export VM_CPU=${VM_CPU:-4}
-export VM_DISK=${VM_DISK:-100}
-export VM_MEMORY_SIZE=${VM_MEMORY_SIZE:-8192}
-export VM_DISK_CACHE=${VM_DISK_CACHE:-unsafe}
-
-# Settings for bifrost
-TEST_PLAYBOOK="opnfv-virtual.yaml"
-USE_INSPECTOR=true
-USE_CIRROS=false
-TESTING_USER=root
-DOWNLOAD_IPA=true
-CREATE_IPA_IMAGE=false
-INSPECT_NODES=true
-INVENTORY_DHCP=false
-INVENTORY_DHCP_STATIC_IP=false
-WRITE_INTERFACES_FILE=true
-
-# Settings for console access
-export DIB_DEV_USER_PWDLESS_SUDO=yes
-export DIB_DEV_USER_PASSWORD=devuser
-
-# Settings for distro: xenial/ubuntu-minimal, 7/centos7, 42.2/suse
-export DIB_OS_RELEASE=${DIB_OS_RELEASE:-xenial}
-export DIB_OS_ELEMENT=${DIB_OS_ELEMENT:-ubuntu-minimal}
-
-# DIB OS packages
-export DIB_OS_PACKAGES=${DIB_OS_PACKAGES:-"vlan,vim,less,bridge-utils,language-pack-en,iputils-ping,rsyslog,curl"}
-
-# Additional dib elements
-export EXTRA_DIB_ELEMENTS=${EXTRA_DIB_ELEMENTS:-"openssh-server"}
-
-# Source Ansible
-set +x +o nounset
-$SCRIPT_HOME/env-setup.sh
-ANSIBLE=$(which ansible-playbook)
-set -x -o nounset
-
-logs_on_exit() {
-    $SCRIPT_HOME/collect-test-info.sh
-}
-trap logs_on_exit EXIT
-
-# Change working directory
-cd $BIFROST_HOME/playbooks
-
-# Syntax check of dynamic inventory test path
-for task in syntax-check list-tasks; do
-    ${ANSIBLE} ${ANSIBLE_VERBOSITY} \
-           -i inventory/localhost \
-           test-bifrost-create-vm.yaml \
-           --${task}
-    ${ANSIBLE} ${ANSIBLE_VERBOSITY} \
-           -i inventory/localhost \
-           ${TEST_PLAYBOOK} \
-           --${task} \
-           -e testing_user=${TESTING_USER}
-done
-
-# Create the VMS
-${ANSIBLE} ${ANSIBLE_VERBOSITY} \
-       -i inventory/localhost \
-       test-bifrost-create-vm.yaml \
-       -e test_vm_num_nodes=${TEST_VM_NUM_NODES} \
-       -e test_vm_memory_size=${VM_MEMORY_SIZE} \
-       -e enable_venv=${ENABLE_VENV} \
-       -e test_vm_domain_type=${VM_DOMAIN_TYPE} \
-       -e ${INVENTORY_FILE_FORMAT}=${BAREMETAL_DATA_FILE}
-
-# Execute the installation and VM startup test
-${ANSIBLE} ${ANSIBLE_VERBOSITY} \
-    -i inventory/bifrost_inventory.py \
-    ${TEST_PLAYBOOK} \
-    -e use_cirros=${USE_CIRROS} \
-    -e testing_user=${TESTING_USER} \
-    -e test_vm_num_nodes=${TEST_VM_NUM_NODES} \
-    -e inventory_dhcp=${INVENTORY_DHCP} \
-    -e inventory_dhcp_static_ip=${INVENTORY_DHCP_STATIC_IP} \
-    -e enable_venv=${ENABLE_VENV} \
-    -e enable_inspector=${USE_INSPECTOR} \
-    -e inspect_nodes=${INSPECT_NODES} \
-    -e download_ipa=${DOWNLOAD_IPA} \
-    -e create_ipa_image=${CREATE_IPA_IMAGE} \
-    -e write_interfaces_file=${WRITE_INTERFACES_FILE} \
-    -e ipv4_gateway=192.168.122.1 \
-    -e wait_timeout=${PROVISION_WAIT_TIMEOUT} \
-    -e enable_keystone=false
-EXITCODE=$?
-
-if [ $EXITCODE != 0 ]; then
-    echo "************************************"
-    echo "Provisioning failed. See logs folder"
-    echo "************************************"
-fi
-
-exit $EXITCODE
diff --git a/prototypes/bifrost/scripts/destroy-env.sh b/prototypes/bifrost/scripts/destroy-env.sh
deleted file mode 100755 (executable)
index c75e814..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 RedHat and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-
-# We need to execute everything as root
-if [[ $(whoami) != "root" ]]; then
-    echo "Error: This script must be run as root!"
-    exit 1
-fi
-
-# Start fresh
-rm -rf /opt/stack
-# HOME is normally set by sudo -H
-rm -rf ${HOME}/.config/openstack
-
-# Delete all libvirt VMs and hosts from vbmc (look for a port number)
-for vm in $(vbmc list | awk '/[0-9]/{{ print $2 }}'); do
-    virsh destroy $vm || true
-    virsh undefine $vm || true
-    vbmc delete $vm
-done
-
-service ironic-conductor stop || true
-
-echo "removing inventory files created by previous builds"
-rm -rf /tmp/baremetal.*
-
-echo "removing ironic database"
-if $(which mysql &> /dev/null); then
-    mysql -u root ironic --execute "drop database ironic;"
-fi
-echo "removing leases"
-[[ -e /var/lib/misc/dnsmasq/dnsmasq.leases ]] && > /var/lib/misc/dnsmasq/dnsmasq.leases
-echo "removing logs"
-rm -rf /var/log/libvirt/baremetal_logs/*
-
-# clean up dib images only if requested explicitly
-CLEAN_DIB_IMAGES=${CLEAN_DIB_IMAGES:-false}
-
-if [ $CLEAN_DIB_IMAGES = "true" ]; then
-    rm -rf /httpboot /tftpboot
-    mkdir /httpboot /tftpboot
-    chmod -R 755 /httpboot /tftpboot
-fi
-
-# remove VM disk images
-rm -rf /var/lib/libvirt/images/*.qcow2
-
-echo "restarting services"
-service dnsmasq restart || true
-service libvirtd restart
-service ironic-api restart || true
-service ironic-conductor start || true
-service ironic-inspector restart || true
diff --git a/prototypes/openstack-ansible/README.md b/prototypes/openstack-ansible/README.md
deleted file mode 100644 (file)
index 34c1d0d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-===============================
-How to deploy OpenStack-Ansible
-===============================
-The script and playbooks defined on this repo will deploy an OpenStack
-cloud based on OpenStack-Ansible.
-It needs to be combined with Bifrost. You need use Bifrost to provide six VMs.
-To learn about how to use Bifrost, you can read the document on
-[/opt/releng/prototypes/bifrost/README.md].
-
-Minimal requirements:
-1. You will need to have a least 150G free space for the partition on where
-   "/var/lib/libvirt/images/" lives.
-2. each vm needs to have at least 8 vCPU, 12 GB RAM, 60 GB HDD.
-
-After provisioning the six VMs please follow that steps:
-
-1.Run the script to deploy OpenStack
-  cd /opt/releng/prototypes/openstack-ansible/scripts/
-  sudo ./osa_deploy.sh
-It will take a lot of time. When the deploy is successful, you will see the
-message "OpenStack deployed successfully".
-
-2.To verify the OpenStack operation
-  2.1 ssh into the controller::
-      ssh 192.168.122.3
-  2.2 Enter into the lxc container::
-      lxcname=$(lxc-ls | grep utility)
-      lxc-attach -n $lxcname
-  2.3 Verify the OpenStack API::
-      source /root/openrc
-      openstack user list
-
-This will show the following output::
-+----------------------------------+--------------------+
-| ID                               | Name               |
-+----------------------------------+--------------------+
-| 056f8fe41336435991fd80872731cada | aodh               |
-| 308f6436e68f40b49d3b8e7ce5c5be1e | glance             |
-| 351b71b43a66412d83f9b3cd75485875 | nova               |
-| 511129e053394aea825cce13b9f28504 | ceilometer         |
-| 5596f71319d44c8991fdc65f3927b62e | gnocchi            |
-| 586f49e3398a4c47a2f6fe50135d4941 | stack_domain_admin |
-| 601b329e6b1d427f9a1e05ed28753497 | heat               |
-| 67fe383b94964a4781345fbcc30ae434 | cinder             |
-| 729bb08351264d729506dad84ed3ccf0 | admin              |
-| 9f2beb2b270940048fe6844f0b16281e | neutron            |
-| fa68f86dd1de4ddbbb7415b4d9a54121 | keystone           |
-+----------------------------------+--------------------+
diff --git a/prototypes/openstack-ansible/file/cinder.yml b/prototypes/openstack-ansible/file/cinder.yml
deleted file mode 100644 (file)
index e40b392..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
----
-# This file contains an example to show how to set
-# the cinder-volume service to run in a container.
-#
-# Important note:
-# When using LVM or any iSCSI-based cinder backends, such as NetApp with
-# iSCSI protocol, the cinder-volume service *must* run on metal.
-# Reference: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1226855
-
-container_skel:
-  cinder_volumes_container:
-    properties:
-      is_metal: false
diff --git a/prototypes/openstack-ansible/file/exports b/prototypes/openstack-ansible/file/exports
deleted file mode 100644 (file)
index 315f79d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# /etc/exports: the access control list for filesystems which may be exported
-#               to NFS clients.  See exports(5).
-#
-# Example for NFSv2 and NFSv3:
-# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
-#
-# Example for NFSv4:
-# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
-# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
-#
-/images         *(rw,sync,no_subtree_check,no_root_squash)
-
diff --git a/prototypes/openstack-ansible/file/modules b/prototypes/openstack-ansible/file/modules
deleted file mode 100644 (file)
index 60a517f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# /etc/modules: kernel modules to load at boot time.
-#
-# This file contains the names of kernel modules that should be loaded
-# at boot time, one per line. Lines beginning with "#" are ignored.
-# Parameters can be specified after the module name.
-
-bonding
-8021q
diff --git a/prototypes/openstack-ansible/file/openstack_user_config.yml b/prototypes/openstack-ansible/file/openstack_user_config.yml
deleted file mode 100644 (file)
index 43e88c0..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
----
-cidr_networks:
-  container: 172.29.236.0/22
-  tunnel: 172.29.240.0/22
-  storage: 172.29.244.0/22
-
-used_ips:
-  - "172.29.236.1,172.29.236.50"
-  - "172.29.240.1,172.29.240.50"
-  - "172.29.244.1,172.29.244.50"
-  - "172.29.248.1,172.29.248.50"
-
-global_overrides:
-  internal_lb_vip_address: 172.29.236.222
-  external_lb_vip_address: 192.168.122.220
-  tunnel_bridge: "br-vxlan"
-  management_bridge: "br-mgmt"
-  provider_networks:
-    - network:
-        container_bridge: "br-mgmt"
-        container_type: "veth"
-        container_interface: "eth1"
-        ip_from_q: "container"
-        type: "raw"
-        group_binds:
-          - all_containers
-          - hosts
-        is_container_address: true
-        is_ssh_address: true
-    - network:
-        container_bridge: "br-vxlan"
-        container_type: "veth"
-        container_interface: "eth10"
-        ip_from_q: "tunnel"
-        type: "vxlan"
-        range: "1:1000"
-        net_name: "vxlan"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-vlan"
-        container_type: "veth"
-        container_interface: "eth12"
-        host_bind_override: "eth12"
-        type: "flat"
-        net_name: "flat"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-vlan"
-        container_type: "veth"
-        container_interface: "eth11"
-        type: "vlan"
-        range: "1:1"
-        net_name: "vlan"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-storage"
-        container_type: "veth"
-        container_interface: "eth2"
-        ip_from_q: "storage"
-        type: "raw"
-        group_binds:
-          - glance_api
-          - cinder_api
-          - cinder_volume
-          - nova_compute
-
-# ##
-# ## Infrastructure
-# ##
-
-# galera, memcache, rabbitmq, utility
-shared-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# repository (apt cache, python packages, etc)
-repo-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# load balancer
-# Ideally the load balancer should not use the Infrastructure hosts.
-# Dedicated hardware is best for improved performance and security.
-haproxy_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# rsyslog server
-# log_hosts:
-# log1:
-#  ip: 172.29.236.14
-
-# ##
-# ## OpenStack
-# ##
-
-# keystone
-identity_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# cinder api services
-storage-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# glance
-# The settings here are repeated for each infra host.
-# They could instead be applied as global settings in
-# user_variables, but are left here to illustrate that
-# each container could have different storage targets.
-image_hosts:
-  controller00:
-    ip: 172.29.236.11
-    container_vars:
-      limit_container_types: glance
-      glance_nfs_client:
-        - server: "172.29.244.15"
-          remote_path: "/images"
-          local_path: "/var/lib/glance/images"
-          type: "nfs"
-          options: "_netdev,auto"
-  controller01:
-    ip: 172.29.236.12
-    container_vars:
-      limit_container_types: glance
-      glance_nfs_client:
-        - server: "172.29.244.15"
-          remote_path: "/images"
-          local_path: "/var/lib/glance/images"
-          type: "nfs"
-          options: "_netdev,auto"
-  controller02:
-    ip: 172.29.236.13
-    container_vars:
-      limit_container_types: glance
-      glance_nfs_client:
-        - server: "172.29.244.15"
-          remote_path: "/images"
-          local_path: "/var/lib/glance/images"
-          type: "nfs"
-          options: "_netdev,auto"
-
-# nova api, conductor, etc services
-compute-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# heat
-orchestration_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# horizon
-dashboard_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# neutron server, agents (L3, etc)
-network_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# ceilometer (telemetry API)
-metering-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# aodh (telemetry alarm service)
-metering-alarm_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# gnocchi (telemetry metrics storage)
-metrics_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# nova hypervisors
-compute_hosts:
-  compute00:
-    ip: 172.29.236.14
-  compute01:
-    ip: 172.29.236.15
-
-# ceilometer compute agent (telemetry)
-metering-compute_hosts:
-  compute00:
-    ip: 172.29.236.14
-  compute01:
-    ip: 172.29.236.15
-# cinder volume hosts (NFS-backed)
-# The settings here are repeated for each infra host.
-# They could instead be applied as global settings in
-# user_variables, but are left here to illustrate that
-# each container could have different storage targets.
-storage_hosts:
-  controller00:
-    ip: 172.29.236.11
-    container_vars:
-      cinder_backends:
-        limit_container_types: cinder_volume
-        lvm:
-          volume_group: cinder-volumes
-          volume_driver: cinder.volume.drivers.lvm.LVMVolumeDriver
-          volume_backend_name: LVM_iSCSI
-          iscsi_ip_address: "172.29.244.11"
-  controller01:
-    ip: 172.29.236.12
-    container_vars:
-      cinder_backends:
-        limit_container_types: cinder_volume
-        lvm:
-          volume_group: cinder-volumes
-          volume_driver: cinder.volume.drivers.lvm.LVMVolumeDriver
-          volume_backend_name: LVM_iSCSI
-          iscsi_ip_address: "172.29.244.12"
-  controller02:
-    ip: 172.29.236.13
-    container_vars:
-      cinder_backends:
-        limit_container_types: cinder_volume
-        lvm:
-          volume_group: cinder-volumes
-          volume_driver: cinder.volume.drivers.lvm.LVMVolumeDriver
-          volume_backend_name: LVM_iSCSI
-          iscsi_ip_address: "172.29.244.13"
diff --git a/prototypes/openstack-ansible/file/opnfv-setup-openstack.yml b/prototypes/openstack-ansible/file/opnfv-setup-openstack.yml
deleted file mode 100644 (file)
index aacdeff..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
----
-# Copyright 2014, Rackspace US, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-- include: os-keystone-install.yml
-- include: os-glance-install.yml
-- include: os-cinder-install.yml
-- include: os-nova-install.yml
-- include: os-neutron-install.yml
-- include: os-heat-install.yml
-- include: os-horizon-install.yml
-- include: os-ceilometer-install.yml
-- include: os-aodh-install.yml
-#NOTE(stevelle) Ensure Gnocchi identities exist before Swift
-- include: os-gnocchi-install.yml
-  when:
-    - gnocchi_storage_driver is defined
-    - gnocchi_storage_driver == 'swift'
-  vars:
-    gnocchi_identity_only: True
-- include: os-swift-install.yml
-- include: os-gnocchi-install.yml
-- include: os-ironic-install.yml
diff --git a/prototypes/openstack-ansible/file/user_variables.yml b/prototypes/openstack-ansible/file/user_variables.yml
deleted file mode 100644 (file)
index 65cbcc1..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
----
-# Copyright 2014, Rackspace US, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# ##
-# ## This file contains commonly used overrides for convenience. Please inspect
-# ## the defaults for each role to find additional override options.
-# ##
-
-# # Debug and Verbose options.
-debug: false
-
-haproxy_keepalived_external_vip_cidr: "192.168.122.220/32"
-haproxy_keepalived_internal_vip_cidr: "172.29.236.222/32"
-haproxy_keepalived_external_interface: br-vlan
-haproxy_keepalived_internal_interface: br-mgmt
diff --git a/prototypes/openstack-ansible/playbooks/configure-targethosts.yml b/prototypes/openstack-ansible/playbooks/configure-targethosts.yml
deleted file mode 100644 (file)
index 538fe17..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
----
-- hosts: all
-  remote_user: root
-  vars_files:
-    - ../var/ubuntu.yml
-  tasks:
-    - name: add public key to host
-      copy:
-        src: ../file/authorized_keys
-        dest: /root/.ssh/authorized_keys
-    - name: configure modules
-      copy:
-        src: ../file/modules
-        dest: /etc/modules
-
-- hosts: controller
-  remote_user: root
-  vars_files:
-    - ../var/ubuntu.yml
-  tasks:
-    - name: configure network
-      template:
-        src: ../template/bifrost/controller.interface.j2
-        dest: /etc/network/interfaces
-      notify:
-        - restart network service
-  handlers:
-    - name: restart network service
-      shell: "/sbin/ifconfig ens3 0 &&/sbin/ifdown -a && /sbin/ifup -a"
-
-- hosts: compute
-  remote_user: root
-  vars_files:
-    - ../var/ubuntu.yml
-  tasks:
-    - name: configure network
-      template:
-        src: ../template/bifrost/compute.interface.j2
-        dest: /etc/network/interfaces
-      notify:
-        - restart network service
-  handlers:
-    - name: restart network service
-      shell: "/sbin/ifconfig ens3 0 &&/sbin/ifdown -a && /sbin/ifup -a"
-
-- hosts: compute01
-  remote_user: root
-  tasks:
-    - name: make nfs dir
-      file: "dest=/images mode=0777 state=directory"
-    - name: configure sdrvice
-      shell: "echo 'nfs        2049/tcp' >>  /etc/services && echo 'nfs        2049/udp' >>  /etc/services"
-    - name: configure NFS
-      copy:
-        src: ../file/exports
-        dest: /etc/exports
-      notify:
-        - restart nfs service
-  handlers:
-    - name: restart nfs service
-      service: name=nfs-kernel-server state=restarted
diff --git a/prototypes/openstack-ansible/playbooks/configure-xcimaster.yml b/prototypes/openstack-ansible/playbooks/configure-xcimaster.yml
deleted file mode 100644 (file)
index fbbde64..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
----
-- hosts: xcimaster
-  remote_user: root
-  vars_files:
-    - ../var/ubuntu.yml
-  tasks:
-    - name: generate SSH keys
-      shell: ssh-keygen -b 2048 -t rsa -f /root/.ssh/id_rsa -q -N ""
-      args:
-        creates: /root/.ssh/id_rsa
-    - name: fetch public key
-      fetch: src="/root/.ssh/id_rsa.pub" dest="/"
-    - name: remove openstack-ansible directories
-      file:
-        path={{ item }}
-        state=absent
-        recurse=no
-      with_items:
-        - "{{OSA_PATH}}"
-        - "{{OSA_ETC_PATH}}"
-    - name: clone openstack-ansible
-      git:
-        repo: "{{OSA_URL}}"
-        dest: "{{OSA_PATH}}"
-        version: "{{OPENSTACK_OSA_VERSION}}"
-    - name: copy opnfv-setup-openstack.yml to /opt/openstack-ansible/playbooks
-      copy:
-        src: ../file/opnfv-setup-openstack.yml
-        dest: "{{OSA_PATH}}/playbooks/opnfv-setup-openstack.yml"
-    - name: copy /opt/openstack-ansible/etc/openstack_deploy to /etc/openstack_deploy
-      shell: "/bin/cp -rf {{OSA_PATH}}/etc/openstack_deploy {{OSA_ETC_PATH}}"
-    - name: bootstrap
-      command: "/bin/bash ./scripts/bootstrap-ansible.sh"
-      args:
-        chdir: "{{OSA_PATH}}"
-    - name: generate password token
-      command: "python pw-token-gen.py --file /etc/openstack_deploy/user_secrets.yml"
-      args:
-        chdir: /opt/openstack-ansible/scripts/
-    - name: copy openstack_user_config.yml to /etc/openstack_deploy
-      copy:
-        src: ../file/openstack_user_config.yml
-        dest: "{{OSA_ETC_PATH}}/openstack_user_config.yml"
-    - name: copy cinder.yml to /etc/openstack_deploy/env.d
-      copy:
-        src: ../file/cinder.yml
-        dest: "{{OSA_ETC_PATH}}/env.d/cinder.yml"
-    - name: copy user_variables.yml to /etc/openstack_deploy/
-      copy:
-        src: ../file/user_variables.yml
-        dest: "{{OSA_ETC_PATH}}/user_variables.yml"
-    - name: configure network
-      template:
-        src: ../template/bifrost/controller.interface.j2
-        dest: /etc/network/interfaces
-      notify:
-        - restart network service
-  handlers:
-    - name: restart network service
-      shell: "/sbin/ifconfig ens3 0 &&/sbin/ifdown -a && /sbin/ifup -a"
-
-- hosts: localhost
-  remote_user: root
-  tasks:
-    - name: Generate authorized_keys
-      shell: "/bin/cat /xcimaster/root/.ssh/id_rsa.pub >> ../file/authorized_keys"
diff --git a/prototypes/openstack-ansible/playbooks/inventory b/prototypes/openstack-ansible/playbooks/inventory
deleted file mode 100644 (file)
index d3768f5..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-[xcimaster]
-xcimaster ansible_ssh_host=192.168.122.2
-
-[controller]
-controller00 ansible_ssh_host=192.168.122.3
-controller01 ansible_ssh_host=192.168.122.4
-controller02 ansible_ssh_host=192.168.122.5
-
-[compute]
-compute00 ansible_ssh_host=192.168.122.6
-compute01 ansible_ssh_host=192.168.122.7
diff --git a/prototypes/openstack-ansible/scripts/osa-deploy.sh b/prototypes/openstack-ansible/scripts/osa-deploy.sh
deleted file mode 100755 (executable)
index ec60744..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-set -o errexit
-set -o nounset
-set -o pipefail
-
-export OSA_PATH=/opt/openstack-ansible
-export LOG_PATH=$OSA_PATH/log
-export PLAYBOOK_PATH=$OSA_PATH/playbooks
-export OSA_BRANCH=${OSA_BRANCH:-"master"}
-XCIMASTER_IP="192.168.122.2"
-
-sudo /bin/rm -rf $LOG_PATH
-sudo /bin/mkdir -p $LOG_PATH
-sudo /bin/cp /root/.ssh/id_rsa.pub ../file/authorized_keys
-echo -e '\n' | sudo tee --append ../file/authorized_keys
-
-# log some info
-echo -e "\n"
-echo "***********************************************************************"
-echo "*                                                                     *"
-echo "*                        Configure XCI Master                         *"
-echo "*                                                                     *"
-echo "*  Bootstrap xci-master, configure network, clone openstack-ansible   *"
-echo "*                Playbooks: configure-xcimaster.yml                   *"
-echo "*                                                                     *"
-echo "***********************************************************************"
-echo -e "\n"
-
-cd ../playbooks/
-# this will prepare the jump host
-# git clone the Openstack-Ansible, bootstrap and configure network
-echo "xci: running ansible playbook configure-xcimaster.yml"
-sudo -E ansible-playbook -i inventory configure-xcimaster.yml
-
-echo "XCI Master is configured successfully!"
-
-# log some info
-echo -e "\n"
-echo "***********************************************************************"
-echo "*                                                                     *"
-echo "*                          Configure Nodes                            *"
-echo "*                                                                     *"
-echo "*       Configure network on OpenStack Nodes, configure NFS           *"
-echo "*                Playbooks: configure-targethosts.yml                 *"
-echo "*                                                                     *"
-echo "***********************************************************************"
-echo -e "\n"
-
-# this will prepare the target host
-# such as configure network and NFS
-echo "xci: running ansible playbook configure-targethosts.yml"
-sudo -E ansible-playbook -i inventory configure-targethosts.yml
-
-echo "Nodes are configured successfully!"
-
-# log some info
-echo -e "\n"
-echo "***********************************************************************"
-echo "*                                                                     *"
-echo "*                       Set Up OpenStack Nodes                        *"
-echo "*                                                                     *"
-echo "*            Set up OpenStack Nodes using openstack-ansible           *"
-echo "*         Playbooks: setup-hosts.yml, setup-infrastructure.yml        *"
-echo "*                                                                     *"
-echo "***********************************************************************"
-echo -e "\n"
-
-# using OpenStack-Ansible deploy the OpenStack
-echo "xci: running ansible playbook setup-hosts.yml"
-sudo -E /bin/sh -c "ssh root@$XCIMASTER_IP openstack-ansible \
-     $PLAYBOOK_PATH/setup-hosts.yml" | \
-     tee $LOG_PATH/setup-hosts.log
-
-# check the result of openstack-ansible setup-hosts.yml
-# if failed, exit with exit code 1
-if grep -q 'failed=1\|unreachable=1' $LOG_PATH/setup-hosts.log; then
-    echo "OpenStack node setup failed!"
-    exit 1
-fi
-
-echo "xci: running ansible playbook setup-infrastructure.yml"
-sudo -E /bin/sh -c "ssh root@$XCIMASTER_IP openstack-ansible \
-     $PLAYBOOK_PATH/setup-infrastructure.yml" | \
-     tee $LOG_PATH/setup-infrastructure.log
-
-# check the result of openstack-ansible setup-infrastructure.yml
-# if failed, exit with exit code 1
-if grep -q 'failed=1\|unreachable=1' $LOG_PATH/setup-infrastructure.log; then
-    echo "OpenStack node setup failed!"
-    exit 1
-fi
-
-echo "OpenStack nodes are setup successfully!"
-
-sudo -E /bin/sh -c "ssh root@$XCIMASTER_IP ansible -i $PLAYBOOK_PATH/inventory/ \
-           galera_container -m shell \
-           -a "mysql -h localhost -e 'show status like \"%wsrep_cluster_%\";'"" \
-           | tee $LOG_PATH/galera.log
-
-if grep -q 'FAILED' $LOG_PATH/galera.log; then
-    echo "Database cluster verification failed!"
-    exit 1
-else
-    echo "Database cluster verification successful!"
-fi
-
-# log some info
-echo -e "\n"
-echo "***********************************************************************"
-echo "*                                                                     *"
-echo "*                           Install OpenStack                         *"
-echo "*                 Playbooks: opnfv-setup-openstack.yml                *"
-echo "*                                                                     *"
-echo "***********************************************************************"
-echo -e "\n"
-
-echo "xci: running ansible playbook opnfv-setup-openstack.yml"
-sudo -E /bin/sh -c "ssh root@$XCIMASTER_IP openstack-ansible \
-     $PLAYBOOK_PATH/opnfv-setup-openstack.yml" | \
-     tee $LOG_PATH/opnfv-setup-openstack.log
-
-if grep -q 'failed=1\|unreachable=1' $LOG_PATH/opnfv-setup-openstack.log; then
-   echo "OpenStack installation failed!"
-   exit 1
-else
-   echo "OpenStack installation is successfully completed!"
-   exit 0
-fi
diff --git a/prototypes/openstack-ansible/template/bifrost/compute.interface.j2 b/prototypes/openstack-ansible/template/bifrost/compute.interface.j2
deleted file mode 100644 (file)
index 1719f6a..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-# This file describes the network interfaces available on your system
-# and how to activate them. For more information, see interfaces(5).
-
-# The loopback network interface
-auto lo
-iface lo inet loopback
-
-
-# Physical interface
-auto ens3
-iface ens3 inet manual
-
-# Container/Host management VLAN interface
-auto ens3.10
-iface ens3.10 inet manual
-    vlan-raw-device ens3
-
-# OpenStack Networking VXLAN (tunnel/overlay) VLAN interface
-auto ens3.30
-iface ens3.30 inet manual
-    vlan-raw-device ens3
-
-# Storage network VLAN interface (optional)
-auto ens3.20
-iface ens3.20 inet manual
-    vlan-raw-device ens3
-
-# Container/Host management bridge
-auto br-mgmt
-iface br-mgmt inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports ens3.10
-    address {{host_info[inventory_hostname].MGMT_IP}}
-    netmask 255.255.252.0
-
-# compute1 VXLAN (tunnel/overlay) bridge config
-auto br-vxlan
-iface br-vxlan inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports ens3.30
-    address {{host_info[inventory_hostname].VXLAN_IP}}
-    netmask 255.255.252.0
-
-# OpenStack Networking VLAN bridge
-auto br-vlan
-iface br-vlan inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports ens3
-    address {{host_info[inventory_hostname].VLAN_IP}}
-    netmask 255.255.255.0
-    gateway 192.168.122.1
-    offload-sg off
-    # Create veth pair, don't bomb if already exists
-    pre-up ip link add br-vlan-veth type veth peer name eth12 || true
-    # Set both ends UP
-    pre-up ip link set br-vlan-veth up
-    pre-up ip link set eth12 up
-    # Delete veth pair on DOWN
-    post-down ip link del br-vlan-veth || true
-    bridge_ports br-vlan-veth
-
-# Add an additional address to br-vlan
-iface br-vlan inet static
-    # Flat network default gateway
-    # -- This needs to exist somewhere for network reachability
-    # -- from the router namespace for floating IP paths.
-    # -- Putting this here is primarily for tempest to work.
-    address {{host_info[inventory_hostname].VLAN_IP_SECOND}}
-    netmask 255.255.252.0
-    dns-nameserver 8.8.8.8 8.8.4.4
-
-# compute1 Storage bridge
-auto br-storage
-iface br-storage inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports ens3.20
-    address {{host_info[inventory_hostname].STORAGE_IP}}
-    netmask 255.255.252.0
diff --git a/prototypes/openstack-ansible/template/bifrost/controller.interface.j2 b/prototypes/openstack-ansible/template/bifrost/controller.interface.j2
deleted file mode 100644 (file)
index 74aeea9..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-# This file describes the network interfaces available on your system
-# and how to activate them. For more information, see interfaces(5).
-
-# The loopback network interface
-auto lo
-iface lo inet loopback
-
-# Physical interface
-auto ens3
-iface ens3 inet manual
-
-# Container/Host management VLAN interface
-auto ens3.10
-iface ens3.10 inet manual
-    vlan-raw-device ens3
-
-# OpenStack Networking VXLAN (tunnel/overlay) VLAN interface
-auto ens3.30
-iface ens3.30 inet manual
-    vlan-raw-device ens3
-
-# Storage network VLAN interface (optional)
-auto ens3.20
-iface ens3.20 inet manual
-    vlan-raw-device ens3
-
-# Container/Host management bridge
-auto br-mgmt
-iface br-mgmt inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports ens3.10
-    address {{host_info[inventory_hostname].MGMT_IP}}
-    netmask 255.255.252.0
-
-# OpenStack Networking VXLAN (tunnel/overlay) bridge
-#
-# Only the COMPUTE and NETWORK nodes must have an IP address
-# on this bridge. When used by infrastructure nodes, the
-# IP addresses are assigned to containers which use this
-# bridge.
-#
-auto br-vxlan
-iface br-vxlan inet manual
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports ens3.30
-
-# OpenStack Networking VLAN bridge
-auto br-vlan
-iface br-vlan inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports ens3
-    address {{host_info[inventory_hostname].VLAN_IP}}
-    netmask 255.255.255.0
-    gateway 192.168.122.1
-    dns-nameserver 8.8.8.8 8.8.4.4
-
-# compute1 Storage bridge
-auto br-storage
-iface br-storage inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports ens3.20
-    address {{host_info[inventory_hostname].STORAGE_IP}}
-    netmask 255.255.252.0
diff --git a/prototypes/openstack-ansible/var/ubuntu.yml b/prototypes/openstack-ansible/var/ubuntu.yml
deleted file mode 100644 (file)
index eb595be..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
----
-OSA_URL: https://git.openstack.org/openstack/openstack-ansible
-OSA_PATH: /opt/openstack-ansible
-OSA_ETC_PATH: /etc/openstack_deploy
-OPENSTACK_OSA_VERSION: "{{ lookup('env','OPENSTACK_OSA_VERSION') }}"
-
-XCIMASTER_IP: 192.168.122.2
-host_info: {'xcimaster':{'MGMT_IP': '172.29.236.10','VLAN_IP': '192.168.122.2', 'STORAGE_IP': '172.29.244.10'},'controller00':{'MGMT_IP': '172.29.236.11','VLAN_IP': '192.168.122.3', 'STORAGE_IP': '172.29.244.11'},'controller01':{'MGMT_IP': '172.29.236.12','VLAN_IP': '192.168.122.4', 'STORAGE_IP': '172.29.244.12'},'controller02':{'MGMT_IP': '172.29.236.13','VLAN_IP': '192.168.122.5', 'STORAGE_IP': '172.29.240.13'},'compute00':{'MGMT_IP': '172.29.236.14','VLAN_IP': '192.168.122.6','VLAN_IP_SECOND': '173.29.241.1','VXLAN_IP': '172.29.240.14', 'STORAGE_IP': '172.29.244.14'},'compute01':{'MGMT_IP': '172.29.236.15','VLAN_IP': '192.168.122.7','VLAN_IP_SECOND': '173.29.241.2','VXLAN_IP': '172.29.240.15', 'STORAGE_IP': '172.29.244.15'}}
diff --git a/prototypes/puppet-infracloud/README.md b/prototypes/puppet-infracloud/README.md
deleted file mode 100644 (file)
index 37d575c..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-===============================
-How to deploy puppet-infracloud
-===============================
-The manifest and mmodules defined on this repo will deploy an OpenStack cloud based on `Infra Cloud <http://docs.openstack.org/infra/system-config/infra-cloud.html>`_ project.
-
-Once all the hardware is provisioned, enter in controller and compute nodes and follow these steps:
-
-1. Clone releng::
-
-    git clone https://gerrit.opnfv.org/gerrit/releng /opt/releng
-
-2. Copy hiera to the right place::
-
-    cp /opt/releng/prototypes/puppet-infracloud/hiera/common.yaml /var/lib/hiera
-
-3. Install modules::
-
-    cd /opt/releng/prototypes/puppet-infracloud
-    ./install_modules.sh
-
-4. Apply the infracloud manifest::
-
-    cd /opt/releng/prototypes/puppet-infracloud
-    puppet apply manifests/site.pp --modulepath=/etc/puppet/modules:/opt/releng/prototypes/puppet-infracloud/modules
-
-5. Once you finish this operation on controller and compute nodes, you will have a functional OpenStack cloud.
-
-In jumphost, follow that steps:
-
-1. Clone releng::
-
-    git clone https://gerrit.opnfv.org/gerrit/releng /opt/releng
-
-2. Create OpenStack clouds config directory::
-
-    mkdir -p /root/.config/openstack
-
-3. Copy credentials file::
-
-    cp /opt/releng/prototypes/puppet-infracloud/creds/clouds.yaml /root/.config/openstack/
-
-4. Install python-dev package as the installation of python-openstackclient depends on it
-
-    apt-get install -y python-dev
-
-5. Install openstack-client. (version 3.2.0 is known to work)::
-
-    pip install python-openstackclient
-
-6. Update /etc/hosts and add controller00::
-
-    192.168.122.3 controller00
-    192.168.122.3 controller00.opnfvlocal controller00
-
-7. Export the desired cloud::
-
-    export OS_CLOUD=opnfv
-
-8. Start using it::
-
-    openstack service list
diff --git a/prototypes/puppet-infracloud/creds/clouds.yaml b/prototypes/puppet-infracloud/creds/clouds.yaml
deleted file mode 100644 (file)
index cc27da2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
----
-clouds:
-  opnfv:
-    verify: False
-    auth:
-      auth_url: https://controller00.opnfvlocal:5000
-      project_name: opnfv
-      username: opnfv
-      password: pass
-    identity_api_version: '3'
-    region_name: RegionOne
-    user_domain_name: opnfv
-    project_domain_name: opnfv
diff --git a/prototypes/puppet-infracloud/deploy_on_baremetal.md b/prototypes/puppet-infracloud/deploy_on_baremetal.md
deleted file mode 100644 (file)
index 2bd0a53..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-How to deploy Infra Cloud on baremetal
-==================================
-
-Install bifrost controller
---------------------------
-First step for deploying Infra Cloud is to install the bifrost controller. This can be virtualized, doesn't need to be on baremetal.
-To achieve that, first we can create a virtual machine with libvirt, with the proper network setup. This VM needs to share one physical interface (the PXE boot one), with the servers for the controller and compute nodes.
-Please follow documentation on: [https://git.openstack.org/cgit/openstack/bifrost/tree/tools/virsh_dev_env/README.md](https://git.openstack.org/cgit/openstack/bifrost/tree/tools/virsh_dev_env/README.md) to get sample templates and instructions for creating the bifrost VM.
-
-Once the **baremetal** VM is finished, you can login by ssh and start installing bifrost there. To proceed, follow this steps:
-
- 1. Change to root user, install git
- 2. Clone releng project (cd /opt, git clone https://gerrit.opnfv.org/gerrit/releng)
- 3. cd /opt/releng/prototypes/puppet-infracloud
- 4. Copy hiera to the right folder (cp hiera/common_baremetal.yaml /var/lib/hiera/common.yaml)
- 5. Ensure hostname is properly set ( hostnamectl set-hostname baremetal.opnfvlocal , hostname -f )
- 6. Install puppet and modules ( ./install_puppet.sh , ./install_modules.sh )
- 7. Apply puppet to install bifrost (puppet apply manifests/site.pp --modulepath=/etc/puppet/modules:/opt/releng/prototypes/puppet-infracloud/modules)
-
- With these steps you will have a bifrost controller up and running.
-
-Deploy baremetal servers
---------------------------
-Once you have bifrost controller ready, you need to use it to start deployment of the baremetal servers.
-On the same bifrost VM, follow these steps:
-
- 1. Source bifrost env vars: source /opt/stack/bifrost/env-vars
- 2. Export baremetal servers inventory:  export BIFROST_INVENTORY-SOURCE=/opt/stack/baremetal.json 
- 3. Change active directory: cd /opt/stack/bifrost/playbooks
- 3. Enroll the servers: ansible-playbook -vvv -i inventory/bifrost_inventory.py enroll-dynamic.yaml -e @/etc/bifrost/bifrost_global_vars
- 4. Deploy the servers:  ansible-playbook -vvv -i inventory/bifrost_inventory.py deploy-dynamic.yaml -e @/etc/bifrost/bifrost_global_vars
- 5. Wait until they are on **active** state, check it with: ironic node-list
-
-In case of some server needing to be redeployed, you can reset it and redeploy again with:
-
- 1. ironic node-set-provision-state <name_of_server> deleted
- 2. Wait and check with ironic node-list until the server is on **available** state
- 3. Redeploy again: ansible-playbook -vvv -i inventory/bifrost_inventory.py deploy-dynamic.yaml -e @/etc/bifrost/bifrost_global_vars
-
-Deploy baremetal servers
---------------------------
-Once all the servers are on **active** state, they can be accessed by ssh and InfraCloud manifests can be deployed on them, to properly deploy a controller and a compute.
-On each of those, follow that steps:
-
- 1. ssh from the bifrost controller to their external ips: ssh root@172.30.13.90
- 2. cd /opt, clone releng project (git clone https://gerrit.opnfv.org/gerrit/releng)
- 3. Copy hiera to the right folder ( cp hiera/common_baremetal.yaml /var/lib/hiera/common.yaml)
- 4. Install modules: ./install_modules.sh
- 5. Apply puppet: puppet apply manifests/site.pp --modulepath=/etc/puppet/modules:/opt/releng/prototypes/puppet-infracloud/modules
-
-Once this has been done on controller and compute, you will have a working cloud. To start working with it, follow that steps:
-
- 1. Ensure that controller00.opnfvlocal resolves properly to the external IP (this is already done in the bifrost controller)
- 2. Copy releng/prototypes/puppet-infracloud/creds/clouds.yaml to $HOME/.config/openstack/clouds.yaml
- 3. Install python-openstackclient
- 4. Specify the cloud you want to use: export OS_CLOUD=opnfvlocal
- 5. Now you can start operating in your cloud with openstack-client: openstack flavor list
-
diff --git a/prototypes/puppet-infracloud/hiera/common.yaml b/prototypes/puppet-infracloud/hiera/common.yaml
deleted file mode 100644 (file)
index 634d96c..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
----
-keystone_rabbit_password: pass
-neutron_rabbit_password: pass
-nova_rabbit_password: pass
-root_mysql_password: pass
-keystone_mysql_password: pass
-glance_mysql_password: pass
-neutron_mysql_password: pass
-nova_mysql_password: pass
-keystone_admin_password: pass
-glance_admin_password: pass
-neutron_admin_password: pass
-nova_admin_password: pass
-keystone_admin_token: token
-ssl_key_file_contents: |
-  -----BEGIN PRIVATE KEY-----
-  MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0YX6wsA/Jhe3q
-  ByoiLsyagO5rOCIyzDsMTV0YMWVIa/QybvS1vI+pK9FIoYPbqWFGHXmQF0DJYulb
-  GnB6A0GlT3YXuaKPucaaANr5hTjuEBF6LuQeq+OIO5u7+l56HGWbbVeB7+vnIxK9
-  43G545aBZSGlUnVfFg+v+IQtmRr36iEa5UDd4sahDXcp2Dm3zGgkFhFKie6AJ4UU
-  TzrH2SL6Nhl7i+AenuoUEDdgDWfGnCXozLngfmhKDi6lHDmh5zJhFS7cKz14wLgF
-  37fsWxxxEX8a6gtGYEEHqXV3x3AXO+U98pr15/xQM9O2O3mrqc/zkmcCRUwCjEeD
-  jEHey3UJAgMBAAECggEAGqapBEwPGRRbsY87b2+AtXdFQrw5eU3pj4jCr3dk4o1o
-  uCbiqxNgGnup4VRT2hmtkKF8O4jj/p1JozdF1RE0GsuhxCGeXiPxrwFfWSyQ28Ou
-  AWJ6O/njlVZRTTXRzbLyZEOEgWNEdJMfCsVXIUL6EsYxcW68fr8QtExAo0gSzvwe
-  IVyhopBy4A1jr5jWqjjlgJhoTHQCkp1e9pHiaW5WWHtk2DFdy6huw5PoDRppG42P
-  soMzqHy9AIWXrYaTGNjyybdJvbaiF0X5Bkr6k8ZxMlRuEb3Vpyrj7SsBrUifRJM3
-  +yheSq3drdQHlw5VrukoIgXGYB4zAQq3LndLoL5YTQKBgQDlzz/hB1IuGOKBXRHy
-  p0j+Lyoxt5EiOW2mdEkbTUYyYnD9EDbJ0wdQ5ijtWLw0J3AwhASkH8ZyljOVHKlY
-  Sq2Oo/uroIH4M8cVIBOJQ2/ak98ItLZ1OMMnDxlZva52jBfYwOEkg6OXeLOLmay6
-  ADfxQ56RFqreVHi9J0/jvpn9UwKBgQDI8CZrM4udJTP7gslxeDcRZw6W34CBBFds
-  49d10Tfd05sysOludzWAfGFj27wqIacFcIyYQmnSga9lBhowv+RwdSjcb2QCCjOb
-  b2GdH+qSFU8BTOcd5FscCBV3U8Y1f/iYp0EQ1/GiG2AYcQC67kjWOO4/JZEXsmtq
-  LisFlWTcswKBgQCC/bs/nViuhei2LELKuafVmzTF2giUJX/m3Wm+cjGNDqew18kj
-  CXKmHks93tKIN+KvBNFQa/xF3G/Skt/EP+zl3XravUbYH0tfM0VvfE0JnjgHUlqe
-  PpiebvDYQlJrqDb/ihHLKm3ZLSfKbvIRo4Y/s3dy5CTJTgT0bLAQ9Nf5mQKBgGqb
-  Dqb9d+rtnACqSNnMn9q5xIHDHlhUx1VcJCm70Fn+NG7WcWJMGLSMSNdD8zafGA/I
-  wK7fPWmTqEx+ylJm3HnVjtI0vuheJTcoBq/oCPlsGLhl5pBzYOskVs8yQQyNUoUa
-  52haSTZqM7eD7JFAbqBJIA2cjrf1zwtMZ0LVGegFAoGBAIFSkI+y4tDEEaSsxrMM
-  OBYEZDkffVar6/mDJukvyn0Q584K3I4eXIDoEEfMGgSN2Tza6QamuNFxOPCH+AAv
-  UKvckK4yuYkc7mQIgjCE8N8UF4kgsXjPek61TZT1QVI1aYFb78ZAZ0miudqWkx4t
-  YSNDj7llArylrPGHBLQ38X4/
-  -----END PRIVATE KEY-----
-ssl_cert_file_contents: |
-  -----BEGIN CERTIFICATE-----
-  MIIDcTCCAlmgAwIBAgIJAJsHSxF0u/oaMA0GCSqGSIb3DQEBCwUAME8xCzAJBgNV
-  BAYTAlVTMQ4wDAYDVQQHDAVXb3JsZDEOMAwGA1UECgwFT1BORlYxIDAeBgNVBAMM
-  F2NvbnRyb2xsZXIwMC5vcG5mdmxvY2FsMB4XDTE2MDgxNzE2MzQwOFoXDTE3MDgx
-  NzE2MzQwOFowTzELMAkGA1UEBhMCVVMxDjAMBgNVBAcMBVdvcmxkMQ4wDAYDVQQK
-  DAVPUE5GVjEgMB4GA1UEAwwXY29udHJvbGxlcjAwLm9wbmZ2bG9jYWwwggEiMA0G
-  CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0YX6wsA/Jhe3qByoiLsyagO5rOCIy
-  zDsMTV0YMWVIa/QybvS1vI+pK9FIoYPbqWFGHXmQF0DJYulbGnB6A0GlT3YXuaKP
-  ucaaANr5hTjuEBF6LuQeq+OIO5u7+l56HGWbbVeB7+vnIxK943G545aBZSGlUnVf
-  Fg+v+IQtmRr36iEa5UDd4sahDXcp2Dm3zGgkFhFKie6AJ4UUTzrH2SL6Nhl7i+Ae
-  nuoUEDdgDWfGnCXozLngfmhKDi6lHDmh5zJhFS7cKz14wLgF37fsWxxxEX8a6gtG
-  YEEHqXV3x3AXO+U98pr15/xQM9O2O3mrqc/zkmcCRUwCjEeDjEHey3UJAgMBAAGj
-  UDBOMB0GA1UdDgQWBBQyFVbU5s2ihD0hX3W7GyHiHZGG1TAfBgNVHSMEGDAWgBQy
-  FVbU5s2ihD0hX3W7GyHiHZGG1TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
-  A4IBAQB+xf7I9RVWzRNjMbWBDE6pBvOWnSksv7Jgr4cREvyOxBDaIoO3uQRDDu6r
-  RCgGs1CuwEaFX1SS/OVrKRFiy9kCU/LBZEFwaHRaL2Kj57Z2yNInPIiKB4h9jen2
-  75fYrpq42XUDSI0NpsqAJpmcQqXOOo8V08FlH0/6h8mWdsfQfbyaf+g73+aRZds8
-  Q4ttmBrqY4Pi5CJW46w7LRCA5o92Di3GI9dAh9MVZ3023cTTjDkW04QbluphuTFj
-  O07Npz162/fHTXut+piV78t+1HlfYWY5TOSQMIVwenftA/Bn8+TQAgnLR+nGo/wu
-  oEaxLtj3Jr07+yIjL88ewT+c3fpq
-  -----END CERTIFICATE-----
-infracloud_mysql_password: pass
-opnfv_password: pass
-
-rabbitmq::package_gpg_key: 'https://www.rabbitmq.com/rabbitmq-release-signing-key.asc'
-rabbitmq::repo::apt::key: '0A9AF2115F4687BD29803A206B73A36E6026DFCA'
-
-hosts:
-  jumphost.opnfvlocal:
-    ip: 192.168.122.2
-  controller00.opnfvlocal:
-    ip: 192.168.122.3
-  compute00.opnfvlocal:
-    ip: 192.168.122.4
-
-bridge_name: br_opnfv
-neutron_subnet_cidr: '192.168.122.0/24'
-neutron_subnet_gateway: '192.168.122.1'
-neutron_subnet_allocation_pools:
-  - 'start=192.168.122.50,end=192.168.122.254'
-virt_type: 'qemu'
diff --git a/prototypes/puppet-infracloud/hiera/common_baremetal.yaml b/prototypes/puppet-infracloud/hiera/common_baremetal.yaml
deleted file mode 100644 (file)
index 015612c..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
----
-keystone_rabbit_password: pass
-neutron_rabbit_password: pass
-nova_rabbit_password: pass
-root_mysql_password: pass
-keystone_mysql_password: pass
-glance_mysql_password: pass
-neutron_mysql_password: pass
-nova_mysql_password: pass
-keystone_admin_password: pass
-glance_admin_password: pass
-neutron_admin_password: pass
-nova_admin_password: pass
-keystone_admin_token: token
-ssl_key_file_contents: |
-  -----BEGIN PRIVATE KEY-----
-  MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0YX6wsA/Jhe3q
-  ByoiLsyagO5rOCIyzDsMTV0YMWVIa/QybvS1vI+pK9FIoYPbqWFGHXmQF0DJYulb
-  GnB6A0GlT3YXuaKPucaaANr5hTjuEBF6LuQeq+OIO5u7+l56HGWbbVeB7+vnIxK9
-  43G545aBZSGlUnVfFg+v+IQtmRr36iEa5UDd4sahDXcp2Dm3zGgkFhFKie6AJ4UU
-  TzrH2SL6Nhl7i+AenuoUEDdgDWfGnCXozLngfmhKDi6lHDmh5zJhFS7cKz14wLgF
-  37fsWxxxEX8a6gtGYEEHqXV3x3AXO+U98pr15/xQM9O2O3mrqc/zkmcCRUwCjEeD
-  jEHey3UJAgMBAAECggEAGqapBEwPGRRbsY87b2+AtXdFQrw5eU3pj4jCr3dk4o1o
-  uCbiqxNgGnup4VRT2hmtkKF8O4jj/p1JozdF1RE0GsuhxCGeXiPxrwFfWSyQ28Ou
-  AWJ6O/njlVZRTTXRzbLyZEOEgWNEdJMfCsVXIUL6EsYxcW68fr8QtExAo0gSzvwe
-  IVyhopBy4A1jr5jWqjjlgJhoTHQCkp1e9pHiaW5WWHtk2DFdy6huw5PoDRppG42P
-  soMzqHy9AIWXrYaTGNjyybdJvbaiF0X5Bkr6k8ZxMlRuEb3Vpyrj7SsBrUifRJM3
-  +yheSq3drdQHlw5VrukoIgXGYB4zAQq3LndLoL5YTQKBgQDlzz/hB1IuGOKBXRHy
-  p0j+Lyoxt5EiOW2mdEkbTUYyYnD9EDbJ0wdQ5ijtWLw0J3AwhASkH8ZyljOVHKlY
-  Sq2Oo/uroIH4M8cVIBOJQ2/ak98ItLZ1OMMnDxlZva52jBfYwOEkg6OXeLOLmay6
-  ADfxQ56RFqreVHi9J0/jvpn9UwKBgQDI8CZrM4udJTP7gslxeDcRZw6W34CBBFds
-  49d10Tfd05sysOludzWAfGFj27wqIacFcIyYQmnSga9lBhowv+RwdSjcb2QCCjOb
-  b2GdH+qSFU8BTOcd5FscCBV3U8Y1f/iYp0EQ1/GiG2AYcQC67kjWOO4/JZEXsmtq
-  LisFlWTcswKBgQCC/bs/nViuhei2LELKuafVmzTF2giUJX/m3Wm+cjGNDqew18kj
-  CXKmHks93tKIN+KvBNFQa/xF3G/Skt/EP+zl3XravUbYH0tfM0VvfE0JnjgHUlqe
-  PpiebvDYQlJrqDb/ihHLKm3ZLSfKbvIRo4Y/s3dy5CTJTgT0bLAQ9Nf5mQKBgGqb
-  Dqb9d+rtnACqSNnMn9q5xIHDHlhUx1VcJCm70Fn+NG7WcWJMGLSMSNdD8zafGA/I
-  wK7fPWmTqEx+ylJm3HnVjtI0vuheJTcoBq/oCPlsGLhl5pBzYOskVs8yQQyNUoUa
-  52haSTZqM7eD7JFAbqBJIA2cjrf1zwtMZ0LVGegFAoGBAIFSkI+y4tDEEaSsxrMM
-  OBYEZDkffVar6/mDJukvyn0Q584K3I4eXIDoEEfMGgSN2Tza6QamuNFxOPCH+AAv
-  UKvckK4yuYkc7mQIgjCE8N8UF4kgsXjPek61TZT1QVI1aYFb78ZAZ0miudqWkx4t
-  YSNDj7llArylrPGHBLQ38X4/
-  -----END PRIVATE KEY-----
-ssl_cert_file_contents: |
-  -----BEGIN CERTIFICATE-----
-  MIIDcTCCAlmgAwIBAgIJAJsHSxF0u/oaMA0GCSqGSIb3DQEBCwUAME8xCzAJBgNV
-  BAYTAlVTMQ4wDAYDVQQHDAVXb3JsZDEOMAwGA1UECgwFT1BORlYxIDAeBgNVBAMM
-  F2NvbnRyb2xsZXIwMC5vcG5mdmxvY2FsMB4XDTE2MDgxNzE2MzQwOFoXDTE3MDgx
-  NzE2MzQwOFowTzELMAkGA1UEBhMCVVMxDjAMBgNVBAcMBVdvcmxkMQ4wDAYDVQQK
-  DAVPUE5GVjEgMB4GA1UEAwwXY29udHJvbGxlcjAwLm9wbmZ2bG9jYWwwggEiMA0G
-  CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0YX6wsA/Jhe3qByoiLsyagO5rOCIy
-  zDsMTV0YMWVIa/QybvS1vI+pK9FIoYPbqWFGHXmQF0DJYulbGnB6A0GlT3YXuaKP
-  ucaaANr5hTjuEBF6LuQeq+OIO5u7+l56HGWbbVeB7+vnIxK943G545aBZSGlUnVf
-  Fg+v+IQtmRr36iEa5UDd4sahDXcp2Dm3zGgkFhFKie6AJ4UUTzrH2SL6Nhl7i+Ae
-  nuoUEDdgDWfGnCXozLngfmhKDi6lHDmh5zJhFS7cKz14wLgF37fsWxxxEX8a6gtG
-  YEEHqXV3x3AXO+U98pr15/xQM9O2O3mrqc/zkmcCRUwCjEeDjEHey3UJAgMBAAGj
-  UDBOMB0GA1UdDgQWBBQyFVbU5s2ihD0hX3W7GyHiHZGG1TAfBgNVHSMEGDAWgBQy
-  FVbU5s2ihD0hX3W7GyHiHZGG1TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
-  A4IBAQB+xf7I9RVWzRNjMbWBDE6pBvOWnSksv7Jgr4cREvyOxBDaIoO3uQRDDu6r
-  RCgGs1CuwEaFX1SS/OVrKRFiy9kCU/LBZEFwaHRaL2Kj57Z2yNInPIiKB4h9jen2
-  75fYrpq42XUDSI0NpsqAJpmcQqXOOo8V08FlH0/6h8mWdsfQfbyaf+g73+aRZds8
-  Q4ttmBrqY4Pi5CJW46w7LRCA5o92Di3GI9dAh9MVZ3023cTTjDkW04QbluphuTFj
-  O07Npz162/fHTXut+piV78t+1HlfYWY5TOSQMIVwenftA/Bn8+TQAgnLR+nGo/wu
-  oEaxLtj3Jr07+yIjL88ewT+c3fpq
-  -----END CERTIFICATE-----
-infracloud_mysql_password: pass
-opnfv_password: pass
-
-rabbitmq::package_gpg_key: 'https://www.rabbitmq.com/rabbitmq-release-signing-key.asc'
-rabbitmq::repo::apt::key: '0A9AF2115F4687BD29803A206B73A36E6026DFCA'
-
-hosts:
-  jumphost.opnfvlocal:
-    ip: 172.30.13.89
-  controller00.opnfvlocal:
-    ip: 172.30.13.90
-  compute00.opnfvlocal:
-    ip: 172.30.13.91
-
-# settings for bifrost
-bridge_name: br_opnfv
-ironic_db_password: pass
-bifrost_mysql_password: pass
-bifrost_ssh_private_key: |
-  -----BEGIN RSA PRIVATE KEY-----
-  MIIEowIBAAKCAQEAvwr2LbfJQuKZDOQse+DQHX84c9LCHvQfy0pu15JkiLM5dUtx
-  hLr/5fxSzblubS4WkNZVsGTtUp51f8yoQyltqquGlVfUf0GO+PCLaRp0arhli0Rl
-  sAGatI12amnrVap82jINiKQRO+UnF97z2hiB35Zxko4jSaPOOiL48DEKowZHL2Ja
-  jjUt6dXcaNotXNaKZpcxz92gdZhFOPU8BrJ/mI9k9u6QI/4qLG/WzW4frHLigA1t
-  OrZ3Nnu3tloWNsS1lh71KRfEv46VD8tCAZfXqJtjdH4Z4AUO++CLF/K4zXhIoFqU
-  Wf8aS64YzoaAfnJ+jUwKs92dVjuFtbEk+t2YLQIDAQABAoIBAQCAr++YaD6oUV9r
-  caANaiiGVhY+3u9oTmXEWMVFbRVPh/riaglzsUuDLm7QqWIbJXqJ4fcitTmv95GK
-  nt+RLizzVEt5+gnoFs8qHU6rY+ibos6z+0TMRKhjiw8DK4oc0JT9nc3EB1CcmgW1
-  bLeyZ+PEKuEiKaDXkAHw43HwyfgyS3Lc90TSaLj3P7egsBuhx1Yy+wgyiPQ/bF0b
-  OBLHHK+nwYLGAq25n/+zA7XAndc2OQd4KzUJcvjyND+IMYnzEbeFH36UcFqbvgGu
-  nR55yIrCxsxcJhhT2slMNtg/xCmo3Jzz1kNBtwbNBik4/5Lkckny0xhQl+h7vz9U
-  +cKjwfK5AoGBAPSy/JHMeQ5/rzbA5LAZhVa/Yc4B5datkwLNg6mh4CzMabJs8AKd
-  de05XB/Nq6Hfp8Aa7zLt2GIb3iqF6w/y+j8YAXS2KQD8/HDs2/9Oxr512kfssk5D
-  dcpTqeIFetzM9pqnctVXBGlbz0QLeL+lT3kXY00+CBm6LjEv8dsPxZr3AoGBAMfd
-  nDnTjUVZ+sRpTBDM3MhKLMETxNWNDaozL+SgpYQwtKlSTfQVdFcM66a8qCFjQFsc
-  /6AjL0bjCA5u859IoQ4ValD0vgkyLHdEN0P1Grf3MK8kjOW1A1s1i2FY6U0z9AM2
-  zsUCA9bB5A9wwxwofoa8VkaDpVSMITbakVoNxJj7AoGAImcft2fmBTHScoJAJLoR
-  0xZpK8t8gug4aQZ34luN5v5+RcWnINb+g3GzEA2cec+2B/5BbwmdiH2eiJ/3YnCo
-  2kIHwl7x+N+Ypk/GxmhO7Owo2j/e+b3mS6HjmpFmqrBuY2PzcyceyalMxKZQPbGC
-  MOYm4e88uFFCuUuiV0gqYhUCgYBmSFhCE6yxeCnoSEbgNicq7SLYMIjEDOqYVpfE
-  9h2ed9qM6IzyQ+SFBBy4+MVGSOfPeRis2DTCnz8pO8i7lEyvy2/cPFPgmue8pZFu
-  2smwqfUlPJxKlgdArzdEO18x3kubNXo9whk614EiEcAX8fVGeK3iak665Pe+fb5z
-  Cqa47wKBgDp3/dgtMneoePKNefy4a9vp5y4XKviC6GOrr0xpEM2ptZ+I7mUJcACN
-  KbaW0dPgtS1cApelmF73IAJRYbKMW7lQzql61IoGw4pGTIMPKerqRs/hTWYPZiSG
-  QHWf3iTV5uQr6cSRoUgkAUHVw2KTGad41RAhDp352iakZuNNBFga
-  -----END RSA PRIVATE KEY-----
-bifrost_ssh_public_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/CvYtt8lC4pkM5Cx74NAdfzhz0sIe9B/LSm7XkmSIszl1S3GEuv/l/FLNuW5tLhaQ1lWwZO1SnnV/zKhDKW2qq4aVV9R/QY748ItpGnRquGWLRGWwAZq0jXZqaetVqnzaMg2IpBE75ScX3vPaGIHflnGSjiNJo846IvjwMQqjBkcvYlqONS3p1dxo2i1c1opmlzHP3aB1mEU49TwGsn+Yj2T27pAj/iosb9bNbh+scuKADW06tnc2e7e2WhY2xLWWHvUpF8S/jpUPy0IBl9eom2N0fhngBQ774IsX8rjNeEigWpRZ/xpLrhjOhoB+cn6NTAqz3Z1WO4W1sST63Zgt yolanda@trasto
-infracloud_vlan: 415
-infracloud_gateway_ip: 172.30.13.1
-default_network_interface: eno3
-dhcp_static_mask: 255.255.255.128
-dhcp_pool_start: 10.20.0.130
-dhcp_pool_end: 10.20.0.254
-network_interface: eth1
-ipv4_nameserver: 8.8.8.8
-ipv4_subnet_mask: 255.255.255.0
-ipv4_gateway: 172.30.13.1
-ironic_inventory:
-  controller00.opnfvlocal:
-    driver: agent_ipmitool
-    driver_info:
-      power:
-        ipmi_address: 172.30.8.90
-        ipmi_username: admin
-    provisioning_ipv4_address: 10.20.0.130
-    ipv4_address: 172.30.13.90
-    ansible_ssh_host: 172.30.13.90
-    ipv4_gateway: 172.30.13.1
-    ipv4_interface_mac: 00:1e:67:f6:9b:35
-    ipv4_subnet_mask: 255.255.255.192
-    name: controller00.opnfvlocal
-    nics:
-      - mac: a4:bf:01:01:a9:fc
-      - mac: 00:1e:67:f6:9b:35
-    properties:
-      cpu_arch: x86_64
-      cpus: '44'
-      disk_size: '1800'
-      ram: '65536'
-    uuid: 00a22849-2442-e511-906e-0012795d96dd
-  compute00.opnfvlocal:
-    driver: agent_ipmitool
-    driver_info:
-      power:
-        ipmi_address: 172.30.8.91
-        ipmi_username: admin
-    provisioning_ipv4_address: 10.20.0.131
-    ipv4_address: 172.30.13.91
-    ansible_ssh_host: 172.30.13.91
-    ipv4_gateway: 172.30.13.1
-    ipv4_interface_mac: 00:1e:67:f6:9b:37
-    ipv4_subnet_mask: 255.255.255.0
-    name: compute00.opnfvlocal
-    nics:
-      - mac: a4:bf:01:01:a9:d4
-      - mac: 00:1e:67:f6:9b:37
-    properties:
-      cpu_arch: x86_64
-      cpus: '44'
-      disk_size: '1800'
-      ram: '65536'
-    uuid: 0051e926-f242-e511-906e-0012795d96dd
-ipmi_passwords: {'172.30.8.90': 'octopus', '172.30.8.91': 'octopus'}
-neutron_subnet_cidr: '172.30.13.0/24'
-neutron_subnet_gateway: '172.30.13.1'
-neutron_subnet_allocation_pools:
-  - 'start=172.30.13.100,end=172.30.13.254'
-virt_type: 'kvm'
-dib_dev_user_password: devuser
diff --git a/prototypes/puppet-infracloud/install_modules.sh b/prototypes/puppet-infracloud/install_modules.sh
deleted file mode 100755 (executable)
index 5d5acd9..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/bin/bash
-# Copyright 2014 OpenStack Foundation.
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-MODULE_PATH=`puppet config print modulepath | cut -d ':' -f 1`
-SCRIPT_NAME=$(basename $0)
-SCRIPT_DIR=$(readlink -f "$(dirname $0)")
-JUST_CLONED=0
-
-function remove_module {
-    local SHORT_MODULE_NAME=$1
-    if [ -n "$SHORT_MODULE_NAME" ]; then
-        rm -Rf "$MODULE_PATH/$SHORT_MODULE_NAME"
-    else
-        echo "ERROR: remove_module requires a SHORT_MODULE_NAME."
-    fi
-}
-
-function git_clone {
-    local MOD=$1
-    local DEST=$2
-
-    JUST_CLONED=1
-    for attempt in $(seq 0 3); do
-        clone_error=0
-        git clone $MOD $DEST && break || true
-        rm -rf $DEST
-        clone_error=1
-    done
-    return $clone_error
-}
-
-# Array of modules to be installed key:value is module:version.
-declare -A MODULES
-
-# Array of modues to be installed from source and without dependency resolution.
-# key:value is source location, revision to checkout
-declare -A SOURCE_MODULES
-
-# Array of modues to be installed from source and without dependency resolution from openstack git
-# key:value is source location, revision to checkout
-declare -A INTEGRATION_MODULES
-
-# load modules.env to populate MODULES[*] and SOURCE_MODULES[*]
-# for processing.
-MODULE_ENV_FILE=${MODULE_FILE:-modules.env}
-MODULE_ENV_PATH=${MODULE_ENV_PATH:-${SCRIPT_DIR}}
-if [ -f "${MODULE_ENV_PATH}/${MODULE_ENV_FILE}" ] ; then
-    . "${MODULE_ENV_PATH}/${MODULE_ENV_FILE}"
-fi
-
-if [ -z "${!MODULES[*]}" ] && [ -z "${!SOURCE_MODULES[*]}" ] ; then
-    echo ""
-    echo "WARNING: nothing to do, unable to find MODULES or SOURCE_MODULES"
-    echo "  export options, try setting MODULE_ENV_PATH or MODULE_ENV_FILE"
-    echo "  export to the proper location of modules.env file."
-    echo ""
-    exit 0
-fi
-
-MODULE_LIST=`puppet module list --color=false`
-
-# Install modules from source
-for MOD in ${!SOURCE_MODULES[*]} ; do
-    JUST_CLONED=0
-    # get the name of the module directory
-    if [ `echo $MOD | awk -F. '{print $NF}'` = 'git' ]; then
-        echo "Remote repos of the form repo.git are not supported: ${MOD}"
-        exit 1
-    fi
-
-    MODULE_NAME=`echo $MOD | awk -F- '{print $NF}'`
-
-    # set up git base command to use the correct path
-    GIT_CMD_BASE="git --git-dir=${MODULE_PATH}/${MODULE_NAME}/.git --work-tree ${MODULE_PATH}/${MODULE_NAME}"
-    # treat any occurrence of the module as a match
-    if ! echo $MODULE_LIST | grep "${MODULE_NAME}" >/dev/null 2>&1; then
-        # clone modules that are not installed
-        git_clone $MOD "${MODULE_PATH}/${MODULE_NAME}"
-    else
-        if [ ! -d ${MODULE_PATH}/${MODULE_NAME}/.git ]; then
-            echo "Found directory ${MODULE_PATH}/${MODULE_NAME} that is not a git repo, deleting it and reinstalling from source"
-            remove_module $MODULE_NAME
-            git_clone $MOD "${MODULE_PATH}/${MODULE_NAME}"
-        elif [ `${GIT_CMD_BASE} remote show origin | grep 'Fetch URL' | awk -F'URL: ' '{print $2}'` != $MOD ]; then
-            echo "Found remote in ${MODULE_PATH}/${MODULE_NAME} that does not match desired remote ${MOD}, deleting dir and re-cloning"
-            remove_module $MODULE_NAME
-            git_clone $MOD "${MODULE_PATH}/${MODULE_NAME}"
-        fi
-    fi
-
-    # fetch the latest refs from the repo
-    if [[ $JUST_CLONED -eq 0 ]] ; then
-        # If we just cloned the repo, we do not need to remote update
-        for attempt in $(seq 0 3); do
-            clone_error=0
-            $GIT_CMD_BASE remote update && break || true
-            clone_error=1
-        done
-        if [[ $clone_error -ne 0 ]] ; then
-            exit $clone_error
-        fi
-    fi
-    # make sure the correct revision is installed, I have to use rev-list b/c rev-parse does not work with tags
-    if [ `${GIT_CMD_BASE} rev-list HEAD --max-count=1` != `${GIT_CMD_BASE} rev-list ${SOURCE_MODULES[$MOD]} --max-count=1` ]; then
-        # checkout correct revision
-        $GIT_CMD_BASE checkout ${SOURCE_MODULES[$MOD]}
-    fi
-done
diff --git a/prototypes/puppet-infracloud/install_puppet.sh b/prototypes/puppet-infracloud/install_puppet.sh
deleted file mode 100755 (executable)
index ae25944..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-#!/bin/bash -x
-
-# Copyright 2013 OpenStack Foundation.
-# Copyright 2013 Hewlett-Packard Development Company, L.P.
-# Copyright 2013 Red Hat, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-#
-# Distro identification functions
-#  note, can't rely on lsb_release for these as we're bare-bones and
-#  it may not be installed yet)
-
-
-function is_fedora {
-    [ -f /usr/bin/yum ] && cat /etc/*release | grep -q -e "Fedora"
-}
-
-function is_rhel7 {
-    [ -f /usr/bin/yum ] && \
-        cat /etc/*release | grep -q -e "Red Hat" -e "CentOS" -e "CloudLinux" && \
-        cat /etc/*release | grep -q 'release 7'
-}
-
-function is_ubuntu {
-    [ -f /usr/bin/apt-get ]
-}
-
-function is_opensuse {
-    [ -f /usr/bin/zypper ] && \
-        cat /etc/os-release | grep -q -e "openSUSE"
-}
-
-function is_gentoo {
-    [ -f /usr/bin/emerge ]
-}
-
-# dnf is a drop-in replacement for yum on Fedora>=22
-YUM=yum
-if is_fedora && [[ $(lsb_release -rs) -ge 22 ]]; then
-    YUM=dnf
-fi
-
-
-#
-# Distro specific puppet installs
-#
-
-function _systemd_update {
-    # there is a bug (rhbz#1261747) where systemd can fail to enable
-    # services due to selinux errors after upgrade.  A work-around is
-    # to install the latest version of selinux and systemd here and
-    # restart the daemon for good measure after it is upgraded.
-    $YUM install -y selinux-policy
-    $YUM install -y systemd
-    systemctl daemon-reload
-}
-
-function setup_puppet_fedora {
-    _systemd_update
-
-    $YUM update -y
-
-    # NOTE: we preinstall lsb_release here to ensure facter sets
-    # lsbdistcodename
-    #
-    # Fedora declares some global hardening flags, which distutils
-    # pick up when building python modules.  redhat-rpm-config
-    # provides the required config options.  Really this should be a
-    # dependency of python-devel (fix in the works, see
-    # https://bugzilla.redhat.com/show_bug.cgi?id=1217376) and can be
-    # removed when that is sorted out.
-
-    $YUM install -y redhat-lsb-core git puppet \
-        redhat-rpm-config
-
-    mkdir -p /etc/puppet/modules/
-
-    # Puppet expects the pip command named as pip-python on
-    # Fedora, as per the packaged command name.  However, we're
-    # installing from get-pip.py so it's just 'pip'.  An easy
-    # work-around is to just symlink pip-python to "fool" it.
-    # See upstream issue:
-    #  https://tickets.puppetlabs.com/browse/PUP-1082
-    ln -fs /usr/bin/pip /usr/bin/pip-python
-    # Wipe out templatedir so we don't get warnings about it
-    sed -i '/templatedir/d' /etc/puppet/puppet.conf
-
-    # upstream is currently looking for /run/systemd files to check
-    # for systemd.  This fails in a chroot where /run isn't mounted
-    # (like when using dib).  Comment out this confine as fedora
-    # always has systemd
-    #  see
-    #   https://github.com/puppetlabs/puppet/pull/4481
-    #   https://bugzilla.redhat.com/show_bug.cgi?id=1254616
-    sudo sed -i.bak  '/^[^#].*/ s|\(^.*confine :exists => \"/run/systemd/system\".*$\)|#\ \1|' \
-        /usr/share/ruby/vendor_ruby/puppet/provider/service/systemd.rb
-
-    # upstream "requests" pip package vendors urllib3 and chardet
-    # packages.  The fedora packages un-vendor this, and symlink those
-    # sub-packages back to packaged versions.  We get into a real mess
-    # of if some of the puppet ends up pulling in "requests" from pip,
-    # and then something like devstack does a "yum install
-    # python-requests" which does a very bad job at overwriting the
-    # pip-installed version (symlinks and existing directories don't
-    # mix).  A solution is to pre-install the python-requests
-    # package; clear it out and re-install from pip.  This way, the
-    # package is installed for dependencies, and we have a pip-managed
-    # requests with correctly vendored sub-packages.
-    sudo ${YUM} install -y python2-requests
-    sudo rm -rf /usr/lib/python2.7/site-packages/requests/*
-    sudo rm -rf /usr/lib/python2.7/site-packages/requests-*.{egg,dist}-info
-    sudo pip install requests
-}
-
-function setup_puppet_rhel7 {
-    local puppet_pkg="https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm"
-
-    # install a bootstrap epel repo to install latest epel-release
-    # package (which provides correct gpg keys, etc); then remove
-    # boostrap
-    cat > /etc/yum.repos.d/epel-bootstrap.repo <<EOF
-[epel-bootstrap]
-name=Bootstrap EPEL
-mirrorlist=https://mirrors.fedoraproject.org/mirrorlist?repo=epel-7&arch=\$basearch
-failovermethod=priority
-enabled=0
-gpgcheck=0
-EOF
-    yum --enablerepo=epel-bootstrap -y install epel-release
-    rm -f /etc/yum.repos.d/epel-bootstrap.repo
-
-    _systemd_update
-    yum update -y
-
-    # NOTE: we preinstall lsb_release to ensure facter sets lsbdistcodename
-    yum install -y redhat-lsb-core git puppet
-
-    rpm -ivh $puppet_pkg
-
-    # see comments in setup_puppet_fedora
-    ln -s /usr/bin/pip /usr/bin/pip-python
-    # Wipe out templatedir so we don't get warnings about it
-    sed -i '/templatedir/d' /etc/puppet/puppet.conf
-
-    # install RDO repo as well; this covers a few things like
-    # openvswitch that aren't available for EPEL
-    yum install -y https://rdoproject.org/repos/rdo-release.rpm
-}
-
-function setup_puppet_ubuntu {
-    if ! which lsb_release > /dev/null 2<&1 ; then
-        DEBIAN_FRONTEND=noninteractive apt-get --option 'Dpkg::Options::=--force-confold' \
-            --assume-yes install -y --force-yes lsb-release
-    fi
-
-    lsbdistcodename=`lsb_release -c -s`
-    if [ $lsbdistcodename != 'trusty' ] ; then
-        rubypkg=rubygems
-    else
-        rubypkg=ruby
-    fi
-
-
-    PUPPET_VERSION=3.*
-    PUPPETDB_VERSION=2.*
-    FACTER_VERSION=2.*
-
-    cat > /etc/apt/preferences.d/00-puppet.pref <<EOF
-Package: puppet puppet-common puppetmaster puppetmaster-common puppetmaster-passenger
-Pin: version $PUPPET_VERSION
-Pin-Priority: 501
-
-Package: puppetdb puppetdb-terminus
-Pin: version $PUPPETDB_VERSION
-Pin-Priority: 501
-
-Package: facter
-Pin: version $FACTER_VERSION
-Pin-Priority: 501
-EOF
-
-    # NOTE(pabelanger): Puppetlabs does not support ubuntu xenial. Instead use
-    # the version of puppet ship by xenial.
-    if [ $lsbdistcodename != 'xenial' ]; then
-        puppet_deb=puppetlabs-release-${lsbdistcodename}.deb
-        if type curl >/dev/null 2>&1; then
-            curl -O http://apt.puppetlabs.com/$puppet_deb
-        else
-            wget http://apt.puppetlabs.com/$puppet_deb -O $puppet_deb
-        fi
-        dpkg -i $puppet_deb
-        rm $puppet_deb
-    fi;
-
-    apt-get update
-    DEBIAN_FRONTEND=noninteractive apt-get --option 'Dpkg::Options::=--force-confold' \
-        --assume-yes dist-upgrade
-    DEBIAN_FRONTEND=noninteractive apt-get --option 'Dpkg::Options::=--force-confold' \
-        --assume-yes install -y --force-yes puppet git $rubypkg
-    # Wipe out templatedir so we don't get warnings about it
-    sed -i '/templatedir/d' /etc/puppet/puppet.conf
-}
-
-function setup_puppet_opensuse {
-    local version=`grep -e "VERSION_ID" /etc/os-release | tr -d "\"" | cut -d "=" -f2`
-    zypper ar http://download.opensuse.org/repositories/systemsmanagement:/puppet/openSUSE_${version}/systemsmanagement:puppet.repo
-    zypper -v --gpg-auto-import-keys --no-gpg-checks -n ref
-    zypper --non-interactive in --force-resolution puppet
-    # Wipe out templatedir so we don't get warnings about it
-    sed -i '/templatedir/d' /etc/puppet/puppet.conf
-}
-
-function setup_puppet_gentoo {
-    echo yes | emaint sync -a
-    emerge -q --jobs=4 puppet-agent
-    sed -i '/templatedir/d' /etc/puppetlabs/puppet/puppet.conf
-}
-
-#
-# pip setup
-#
-
-function setup_pip {
-    # Install pip using get-pip
-    local get_pip_url=https://bootstrap.pypa.io/get-pip.py
-    local ret=1
-
-    if [ -f ./get-pip.py ]; then
-        ret=0
-    elif type curl >/dev/null 2>&1; then
-        curl -O $get_pip_url
-        ret=$?
-    elif type wget >/dev/null 2>&1; then
-        wget $get_pip_url
-        ret=$?
-    fi
-
-    if [ $ret -ne 0 ]; then
-        echo "Failed to get get-pip.py"
-        exit 1
-    fi
-
-    if is_opensuse; then
-        zypper --non-interactive in --force-resolution python python-xml
-    fi
-
-    python get-pip.py
-    rm get-pip.py
-
-    # we are about to overwrite setuptools, but some packages we
-    # install later might depend on the python-setuptools package.  To
-    # avoid later conflicts, and because distro packages don't include
-    # enough info for pip to certain it can fully uninstall the old
-    # package, for safety we clear it out by hand (this seems to have
-    # been a problem with very old to new updates, e.g. centos6 to
-    # current-era, but less so for smaller jumps).  There is a bit of
-    # chicken-and-egg problem with pip in that it requires setuptools
-    # for some operations, such as wheel creation.  But just
-    # installing setuptools shouldn't require setuptools itself, so we
-    # are safe for this small section.
-    if is_rhel7 || is_fedora; then
-        yum install -y python-setuptools
-        rm -rf /usr/lib/python2.7/site-packages/setuptools*
-    fi
-
-    pip install -U setuptools
-}
-
-setup_pip
-
-if is_fedora; then
-    setup_puppet_fedora
-elif is_rhel7; then
-    setup_puppet_rhel7
-elif is_ubuntu; then
-    setup_puppet_ubuntu
-elif is_opensuse; then
-    setup_puppet_opensuse
-elif is_gentoo; then
-    setup_puppet_gentoo
-else
-    echo "*** Can not setup puppet: distribution not recognized"
-    exit 1
-fi
-
diff --git a/prototypes/puppet-infracloud/manifests/site.pp b/prototypes/puppet-infracloud/manifests/site.pp
deleted file mode 100644 (file)
index 3483b06..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 RedHat and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-node 'controller00.opnfvlocal' {
-  $group = 'infracloud'
-  include ::sudoers
-
-  class { '::opnfv::server':
-    iptables_public_tcp_ports => [80,5000,5671,8774,9292,9696,35357], # logs,keystone,rabbit,nova,glance,neutron,keystone
-    sysadmins                 => hiera('sysadmins', []),
-    enable_unbound            => false,
-    purge_apt_sources         => false,
-  }
-  class { '::opnfv::controller':
-    keystone_rabbit_password         => hiera('keystone_rabbit_password'),
-    neutron_rabbit_password          => hiera('neutron_rabbit_password'),
-    nova_rabbit_password             => hiera('nova_rabbit_password'),
-    root_mysql_password              => hiera('infracloud_mysql_password'),
-    keystone_mysql_password          => hiera('keystone_mysql_password'),
-    glance_mysql_password            => hiera('glance_mysql_password'),
-    neutron_mysql_password           => hiera('neutron_mysql_password'),
-    nova_mysql_password              => hiera('nova_mysql_password'),
-    keystone_admin_password          => hiera('keystone_admin_password'),
-    glance_admin_password            => hiera('glance_admin_password'),
-    neutron_admin_password           => hiera('neutron_admin_password'),
-    nova_admin_password              => hiera('nova_admin_password'),
-    keystone_admin_token             => hiera('keystone_admin_token'),
-    ssl_key_file_contents            => hiera('ssl_key_file_contents'),
-    ssl_cert_file_contents           => hiera('ssl_cert_file_contents'),
-    br_name                          => hiera('bridge_name'),
-    controller_public_address        => $::fqdn,
-    neutron_subnet_cidr              => hiera('neutron_subnet_cidr'),
-    neutron_subnet_gateway           => hiera('neutron_subnet_gateway'),
-    neutron_subnet_allocation_pools  => hiera('neutron_subnet_allocation_pools'),
-    opnfv_password                   => hiera('opnfv_password'),
-    require                          => Class['::opnfv::server'],
-  }
-}
-
-node 'compute00.opnfvlocal' {
-  $group = 'infracloud'
-  include ::sudoers
-
-  class { '::opnfv::server':
-    sysadmins                 => hiera('sysadmins', []),
-    enable_unbound            => false,
-    purge_apt_sources         => false,
-  }
-
-  class { '::opnfv::compute':
-    nova_rabbit_password             => hiera('nova_rabbit_password'),
-    neutron_rabbit_password          => hiera('neutron_rabbit_password'),
-    neutron_admin_password           => hiera('neutron_admin_password'),
-    ssl_cert_file_contents           => hiera('ssl_cert_file_contents'),
-    ssl_key_file_contents            => hiera('ssl_key_file_contents'),
-    br_name                          => hiera('bridge_name'),
-    controller_public_address        => 'controller00.opnfvlocal',
-    virt_type                        => hiera('virt_type'),
-    require                          => Class['::opnfv::server'],
-  }
-}
-
-node 'jumphost.opnfvlocal' {
-  class { '::opnfv::server':
-    sysadmins                 => hiera('sysadmins', []),
-    enable_unbound            => false,
-    purge_apt_sources         => false,
-  }
-}
-
-node 'baremetal.opnfvlocal', 'lfpod5-jumpserver' {
-  class { '::opnfv::server':
-    iptables_public_udp_ports => [67, 69],
-    sysadmins                 => hiera('sysadmins', []),
-    enable_unbound            => false,
-    purge_apt_sources         => false,
-  }
-
-  class { '::infracloud::bifrost':
-    ironic_inventory          => hiera('ironic_inventory', {}),
-    ironic_db_password        => hiera('ironic_db_password'),
-    mysql_password            => hiera('bifrost_mysql_password'),
-    ipmi_passwords            => hiera('ipmi_passwords'),
-    ssh_private_key           => hiera('bifrost_ssh_private_key'),
-    ssh_public_key            => hiera('bifrost_ssh_public_key'),
-    vlan                      => hiera('infracloud_vlan'),
-    gateway_ip                => hiera('infracloud_gateway_ip'),
-    default_network_interface => hiera('default_network_interface'),
-    dhcp_static_mask          => hiera('dhcp_static_mask'),
-    dhcp_pool_start           => hiera('dhcp_pool_start'),
-    dhcp_pool_end             => hiera('dhcp_pool_end'),
-    network_interface         => hiera('network_interface'),
-    ipv4_nameserver           => hiera('ipv4_nameserver'),
-    ipv4_subnet_mask          => hiera('ipv4_subnet_mask'),
-    bridge_name               => hiera('bridge_name'),
-    dib_dev_user_password     => hiera('dib_dev_user_password'),
-    require                   => Class['::opnfv::server'],
-  }
-}
diff --git a/prototypes/puppet-infracloud/modules.env b/prototypes/puppet-infracloud/modules.env
deleted file mode 100644 (file)
index 9c07ec9..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright 2014 OpenStack Foundation.
-# Copyright 2016 RedHat.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# load additional modules from modules.env
-# modules.env should exist in the same folder as install_modules.sh
-#
-# - use export MODULE_FILE to specify an alternate config
-#   when calling install_modules.sh.
-#   This allows for testing environments that are configured with alternate
-#   module configuration.
-
-# Source modules should use tags, explicit refs or remote branches because
-# we do not update local branches in this script.
-# Keep sorted
-
-OPENSTACK_GIT_ROOT=https://git.openstack.org
-
-# InfraCloud modules
-SOURCE_MODULES["$OPENSTACK_GIT_ROOT/openstack/puppet-cinder"]="origin/stable/mitaka"
-SOURCE_MODULES["$OPENSTACK_GIT_ROOT/openstack/puppet-glance"]="origin/stable/mitaka"
-SOURCE_MODULES["$OPENSTACK_GIT_ROOT/openstack/puppet-ironic"]="origin/stable/mitaka"
-SOURCE_MODULES["$OPENSTACK_GIT_ROOT/openstack/puppet-keystone"]="origin/stable/mitaka"
-SOURCE_MODULES["$OPENSTACK_GIT_ROOT/openstack/puppet-neutron"]="origin/stable/mitaka"
-SOURCE_MODULES["$OPENSTACK_GIT_ROOT/openstack/puppet-nova"]="origin/stable/mitaka"
-SOURCE_MODULES["$OPENSTACK_GIT_ROOT/openstack/puppet-openstack_extras"]="origin/stable/mitaka"
-SOURCE_MODULES["$OPENSTACK_GIT_ROOT/openstack/puppet-openstacklib"]="origin/stable/mitaka"
-
-SOURCE_MODULES["https://git.openstack.org/openstack-infra/puppet-vcsrepo"]="0.0.8"
-SOURCE_MODULES["https://github.com/duritong/puppet-sysctl"]="v0.0.11"
-SOURCE_MODULES["https://github.com/nanliu/puppet-staging"]="1.0.0"
-SOURCE_MODULES["https://github.com/jfryman/puppet-selinux"]="v0.2.5"
-SOURCE_MODULES["https://github.com/maestrodev/puppet-wget"]="v1.6.0"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-apache"]="1.8.1"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-apt"]="2.1.0"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-concat"]="1.2.5"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-firewall"]="1.1.3"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-haproxy"]="1.5.0"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-inifile"]="1.1.3"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-mysql"]="3.6.2"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-ntp"]="3.2.1"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-rabbitmq"]="5.2.3"
-SOURCE_MODULES["https://github.com/puppetlabs/puppetlabs-stdlib"]="4.10.0"
-SOURCE_MODULES["https://github.com/rafaelfelix/puppet-pear"]="1.0.3"
-SOURCE_MODULES["https://github.com/saz/puppet-memcached"]="v2.6.0"
-SOURCE_MODULES["https://github.com/saz/puppet-timezone"]="v3.3.0"
-SOURCE_MODULES["https://github.com/stankevich/puppet-python"]="1.9.4"
-SOURCE_MODULES["https://github.com/vamsee/puppet-solr"]="0.0.8"
-SOURCE_MODULES["https://github.com/voxpupuli/puppet-alternatives"]="0.3.0"
-SOURCE_MODULES["https://github.com/voxpupuli/puppet-archive"]="v0.5.1"
-SOURCE_MODULES["https://github.com/voxpupuli/puppet-git_resource"]="0.3.0"
-SOURCE_MODULES["https://github.com/voxpupuli/puppet-nodejs"]="1.2.0"
-SOURCE_MODULES["https://github.com/voxpupuli/puppet-puppetboard"]="2.4.0"
-
-
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-ansible"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-httpd"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-infracloud"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-iptables"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-logrotate"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-pip"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-snmpd"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-ssh"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-ssl_cert_check"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-sudoers"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-ulimit"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-unattended_upgrades"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-unbound"]="origin/master"
-INTEGRATION_MODULES["$OPENSTACK_GIT_ROOT/openstack-infra/puppet-user"]="origin/master"
-
-for MOD in ${!INTEGRATION_MODULES[*]}; do
- SOURCE_MODULES[$MOD]=${INTEGRATION_MODULES[$MOD]}
-done
diff --git a/prototypes/puppet-infracloud/modules/opnfv/manifests/compute.pp b/prototypes/puppet-infracloud/modules/opnfv/manifests/compute.pp
deleted file mode 100644 (file)
index ca548a5..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-class opnfv::compute (
-  $nova_rabbit_password,
-  $neutron_rabbit_password,
-  $neutron_admin_password,
-  $ssl_cert_file_contents,
-  $ssl_key_file_contents,
-  $br_name,
-  $controller_public_address,
-  $virt_type = 'kvm',
-) {
-  class { '::infracloud::compute':
-    nova_rabbit_password          => $nova_rabbit_password,
-    neutron_rabbit_password       => $neutron_rabbit_password,
-    neutron_admin_password        => $neutron_admin_password,
-    ssl_cert_file_contents        => $ssl_cert_file_contents,
-    ssl_key_file_contents         => $ssl_key_file_contents,
-    br_name                       => $br_name,
-    controller_public_address     => $controller_public_address,
-    virt_type                     => $virt_type,
-  }
-
-}
-
diff --git a/prototypes/puppet-infracloud/modules/opnfv/manifests/controller.pp b/prototypes/puppet-infracloud/modules/opnfv/manifests/controller.pp
deleted file mode 100644 (file)
index 7522692..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 RedHat and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-class opnfv::controller (
-  $keystone_rabbit_password,
-  $neutron_rabbit_password,
-  $nova_rabbit_password,
-  $root_mysql_password,
-  $keystone_mysql_password,
-  $glance_mysql_password,
-  $neutron_mysql_password,
-  $nova_mysql_password,
-  $glance_admin_password,
-  $keystone_admin_password,
-  $neutron_admin_password,
-  $nova_admin_password,
-  $keystone_admin_token,
-  $ssl_key_file_contents,
-  $ssl_cert_file_contents,
-  $br_name,
-  $controller_public_address = $::fqdn,
-  $neutron_subnet_cidr,
-  $neutron_subnet_gateway,
-  $neutron_subnet_allocation_pools,
-  $opnfv_password,
-  $opnfv_email = 'opnfvuser@gmail.com',
-) {
-  class { '::infracloud::controller':
-    keystone_rabbit_password         => $keystone_rabbit_password,
-    neutron_rabbit_password          => $neutron_rabbit_password,
-    nova_rabbit_password             => $nova_rabbit_password,
-    root_mysql_password              => $root_mysql_password,
-    keystone_mysql_password          => $keystone_mysql_password,
-    glance_mysql_password            => $glance_mysql_password,
-    neutron_mysql_password           => $neutron_mysql_password,
-    nova_mysql_password              => $nova_mysql_password,
-    keystone_admin_password          => $keystone_admin_password,
-    glance_admin_password            => $glance_admin_password,
-    neutron_admin_password           => $neutron_admin_password,
-    nova_admin_password              => $nova_admin_password,
-    keystone_admin_token             => $keystone_admin_token,
-    ssl_key_file_contents            => $ssl_key_file_contents,
-    ssl_cert_file_contents           => $ssl_cert_file_contents,
-    br_name                          => $br_name,
-    controller_public_address        => $controller_public_address,
-    neutron_subnet_cidr              => $neutron_subnet_cidr,
-    neutron_subnet_gateway           => $neutron_subnet_gateway,
-    neutron_subnet_allocation_pools  => $neutron_subnet_allocation_pools,
-  }
-
-  # create keystone creds
-  keystone_domain { 'opnfv':
-    ensure  => present,
-    enabled => true,
-  }
-
-  keystone_tenant { 'opnfv':
-    ensure      => present,
-    enabled     => true,
-    description => 'OPNFV cloud',
-    domain      => 'opnfv',
-    require     => Keystone_domain['opnfv'],
-  }
-
-  keystone_user { 'opnfv':
-    ensure   => present,
-    enabled  => true,
-    domain   => 'opnfv',
-    email    => $opnfv_email,
-    password => $opnfv_password,
-    require  => Keystone_tenant['opnfv'],
-  }
-
-  keystone_role { 'user': ensure => present }
-
-  keystone_user_role { 'opnfv::opnfv@opnfv::opnfv':
-    roles => [ 'user', 'admin', ],
-  }
-}
-
diff --git a/prototypes/puppet-infracloud/modules/opnfv/manifests/server.pp b/prototypes/puppet-infracloud/modules/opnfv/manifests/server.pp
deleted file mode 100644 (file)
index d167973..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2016 RedHat and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-class opnfv::server (
-  $iptables_public_tcp_ports = [],
-  $iptables_public_udp_ports = [],
-  $iptables_rules4           = [],
-  $iptables_rules6           = [],
-  $sysadmins                 = [],
-  $enable_unbound            = true,
-  $purge_apt_sources         = true,
-) {
-  ###########################################################
-  # Classes for all hosts
-
-  include snmpd
-
-  class { 'iptables':
-    public_tcp_ports => $iptables_public_tcp_ports,
-    public_udp_ports => $iptables_public_udp_ports,
-    rules4           => $iptables_rules4,
-    rules6           => $iptables_rules6,
-  }
-
-  class { 'timezone':
-    timezone => 'Etc/UTC',
-  }
-
-  if ($enable_unbound) {
-    class { 'unbound':
-      install_resolv_conf => $install_resolv_conf
-    }
-  }
-
-  if ($::in_chroot) {
-    notify { 'rsyslog in chroot':
-      message => 'rsyslog not refreshed, running in chroot',
-    }
-    $rsyslog_notify = []
-  } else {
-    service { 'rsyslog':
-      ensure     => running,
-      enable     => true,
-      hasrestart => true,
-      require    => Package['rsyslog'],
-    }
-    $rsyslog_notify = [ Service['rsyslog'] ]
-  }
-
-  ###########################################################
-  # System tweaks
-
-  # Increase syslog message size in order to capture
-  # python tracebacks with syslog.
-  file { '/etc/rsyslog.d/99-maxsize.conf':
-    ensure  => present,
-    # Note MaxMessageSize is not a puppet variable.
-    content => '$MaxMessageSize 6k',
-    owner   => 'root',
-    group   => 'root',
-    mode    => '0644',
-    notify  => $rsyslog_notify,
-    require => Package['rsyslog'],
-  }
-
-  # We don't like byobu
-  file { '/etc/profile.d/Z98-byobu.sh':
-    ensure => absent,
-  }
-
-  if $::osfamily == 'Debian' {
-
-    # Ubuntu installs their whoopsie package by default, but it eats through
-    # memory and we don't need it on servers
-    package { 'whoopsie':
-      ensure => absent,
-    }
-
-    package { 'popularity-contest':
-      ensure => absent,
-    }
-  }
-
-  ###########################################################
-  # Package resources for all operating systems
-
-  package { 'at':
-    ensure => present,
-  }
-
-  package { 'lvm2':
-    ensure => present,
-  }
-
-  package { 'strace':
-    ensure => present,
-  }
-
-  package { 'tcpdump':
-    ensure => present,
-  }
-
-  package { 'rsyslog':
-    ensure => present,
-  }
-
-  package { 'git':
-    ensure => present,
-  }
-
-  package { 'rsync':
-    ensure => present,
-  }
-
-  case $::osfamily {
-    'RedHat': {
-      $packages = ['parted', 'puppet', 'wget', 'iputils']
-      $user_packages = ['emacs-nox', 'vim-enhanced']
-      $update_pkg_list_cmd = ''
-    }
-    'Debian': {
-      $packages = ['parted', 'puppet', 'wget', 'iputils-ping']
-      case $::operatingsystemrelease {
-        /^(12|14)\.(04|10)$/: {
-          $user_packages = ['emacs23-nox', 'vim-nox', 'iftop',
-                            'sysstat', 'iotop']
-        }
-        default: {
-          $user_packages = ['emacs-nox', 'vim-nox']
-        }
-      }
-      $update_pkg_list_cmd = 'apt-get update >/dev/null 2>&1;'
-    }
-    default: {
-      fail("Unsupported osfamily: ${::osfamily} The 'openstack_project' module only supports osfamily Debian or RedHat (slaves only).")
-    }
-  }
-  package { $packages:
-    ensure => present
-  }
-
-  ###########################################################
-  # Package resources for specific operating systems
-
-  case $::osfamily {
-    'Debian': {
-      # Purge and augment existing /etc/apt/sources.list if requested, and make
-      # sure apt-get update is run before any packages are installed
-      class { '::apt':
-        purge => { 'sources.list' => $purge_apt_sources }
-      }
-
-      # Make sure dig is installed
-      package { 'dnsutils':
-        ensure => present,
-      }
-    }
-    'RedHat': {
-      # Make sure dig is installed
-      package { 'bind-utils':
-        ensure => present,
-      }
-    }
-  }
-
-  ###########################################################
-  # Manage  ntp
-
-  include '::ntp'
-
-  if ($::osfamily == "RedHat") {
-    # Utils in ntp-perl are included in Debian's ntp package; we
-    # add it here for consistency.  See also
-    # https://tickets.puppetlabs.com/browse/MODULES-3660
-    package { 'ntp-perl':
-      ensure => present
-    }
-    # NOTE(pabelanger): We need to ensure ntpdate service starts on boot for
-    # centos-7.  Currently, ntpd explicitly require ntpdate to be running before
-    # the sync process can happen in ntpd.  As a result, if ntpdate is not
-    # running, ntpd will start but fail to sync because of DNS is not properly
-    # setup.
-    package { 'ntpdate':
-      ensure => present,
-    }
-    service { 'ntpdate':
-      enable => true,
-      require => Package['ntpdate'],
-    }
-  }
-
-  ###########################################################
-  # Manage  python/pip
-
-  $desired_virtualenv = '13.1.0'
-  class { '::pip':
-    optional_settings => {
-      'extra-index-url' => '',
-    },
-    manage_pip_conf => true,
-  }
-
-  if (( versioncmp($::virtualenv_version, $desired_virtualenv) < 0 )) {
-    $virtualenv_ensure = $desired_virtualenv
-  } else {
-    $virtualenv_ensure = present
-  }
-  package { 'virtualenv':
-    ensure   => $virtualenv_ensure,
-    provider => openstack_pip,
-    require  => Class['pip'],
-  }
-
-  # manage root ssh
-  if ! defined(File['/root/.ssh']) {
-    file { '/root/.ssh':
-      ensure => directory,
-      mode   => '0700',
-    }
-  }
-
-  # ensure that we have non-pass sudo, and
-  # not require tty
-  file_line { 'sudo_rule_no_pw':
-    path => '/etc/sudoers',
-    line => '%wheel     ALL=(ALL)       NOPASSWD: ALL',
-  }
-  file_line { 'sudo_rule_notty':
-    path   => '/etc/sudoers',
-    line   => 'Defaults    requiretty',
-    match  => '.*requiretty.*',
-    match_for_absence => true,
-    ensure => absent,
-    multiple => true,
-  }
-
-  # update hosts
-  create_resources('host', hiera_hash('hosts'))
-}
diff --git a/prototypes/xci/README.rst b/prototypes/xci/README.rst
deleted file mode 100644 (file)
index ecb8e19..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-###########################
-OPNFV XCI Developer Sandbox
-###########################
-
-The XCI Developer Sandbox is created by the OPNFV community for the OPNFV
-community in order to
-
-- provide means for OPNFV developers to work with OpenStack master branch,
-  cutting the time it takes to develop new features significantly and testing
-  them on OPNFV Infrastructure
-- enable OPNFV developers to identify bugs earlier, issue fixes faster, and
-  get feedback on a daily basis
-- establish mechanisms to run additional testing on OPNFV Infrastructure to
-  provide feedback to OpenStack community
-- make the solutions we put in place available to other LF Networking Projects
-  OPNFV works with closely
-
-More information about OPNFV XCI and the sandbox can be seen on
-`OPNFV Wiki <https://wiki.opnfv.org/pages/viewpage.action?pageId=8687635>`_.
-
-===================================
-Components of XCI Developer Sandbox
-===================================
-
-The sandbox uses OpenStack projects for VM node creation, provisioning
-and OpenStack installation.
-
-- **openstack/bifrost:** Bifrost (pronounced bye-frost) is a set of Ansible
-  playbooks that automates the task of deploying a base image onto a set
-  of known hardware using ironic. It provides modular utility for one-off
-  operating system deployment with as few operational requirements as
-  reasonably possible. Bifrost supports different operating systems such as
-  Ubuntu, CentOS, and openSUSE.
-  More information about this project can be seen on
-  `Bifrost documentation <https://docs.openstack.org/developer/bifrost/>`_.
-
-- **openstack/openstack-ansible:** OpenStack-Ansible is an official OpenStack
-  project which aims to deploy production environments from source in a way
-  that makes it scalable while also being simple to operate, upgrade, and grow.
-  More information about this project can be seen on
-  `OpenStack Ansible documentation <https://docs.openstack.org/developer/openstack-ansible/>`_.
-
-- **opnfv/releng:** OPNFV Releng Project provides additional scripts, Ansible
-  playbooks and configuration options in order for developers to have easy
-  way of using openstack/bifrost and openstack/openstack-ansible by just
-  setting couple of environment variables and executing a single script.
-  More infromation about this project can be seen on
-  `OPNFV Releng documentation <https://wiki.opnfv.org/display/releng>_`.
-
-==========
-Basic Flow
-==========
-
-Here are the steps that take place upon the execution of the sandbox script
-``xci-deploy.sh``:
-
-1. Sources environment variables in order to set things up properly.
-2. Installs ansible on the host where sandbox script is executed.
-3. Creates and provisions VM nodes based on the flavor chosen by the user.
-4. Configures the host where the sandbox script is executed.
-5. Configures the deployment host which the OpenStack installation will
-   be driven from.
-6. Configures the target hosts where OpenStack will be installed.
-7. Configures the target hosts as controller(s) and compute(s) nodes.
-8. Starts the OpenStack installation.
-
-=====================
-Sandbox Prerequisites
-=====================
-
-In order to use this sandbox, the host must have certain packages installed.
-
-- libvirt
-- python
-- pip
-- git
-- <fix the list with all the dependencies>
-- passwordless sudo
-
-The host must also have enough CPU/RAM/Disk in order to host number of VM
-nodes that will be created based on the chosen flavor. See the details from
-`this link <https://wiki.opnfv.org/display/INF/XCI+Developer+Sandbox#XCIDeveloperSandbox-Prerequisites>`_.
-
-===========================
-Flavors Provided by Sandbox
-===========================
-
-OPNFV XCI Sandbox provides different flavors such as all in one (aio) which
-puts much lower requirements on the host machine and full-blown HA.
-
-* aio: Single node which acts as the deployment host, controller and compute.
-* mini: One deployment host, 1 controller node and 1 compute node.
-* noha: One deployment host, 1 controller node and 2 compute nodes.
-* ha: One deployment host, 3 controller nodes and 2 compute nodes.
-
-See the details of the flavors from
-`this link <https://wiki.opnfv.org/display/INF/XCI+Developer+Sandbox#XCIDeveloperSandbox-AvailableFlavors>`_.
-
-==========
-How to Use
-==========
-
-Basic Usage
------------
-
-clone OPNFV Releng repository
-
-    git clone https://gerrit.opnfv.org/gerrit/releng.git
-
-change into directory where the sandbox script is located
-
-    cd releng/prototypes/xci
-
-execute sandbox script
-
-    ./xci-deploy.sh
-
-Issuing above command will start aio sandbox deployment and the sandbox
-should be ready between 1,5 and 2 hours depending on the host machine.
-
-Please remember that the user executing the XCI script will need to
-have an ssh key available, and stored in $HOME/.ssh directory.
-You can generate one by executing
-
-    ssh-keygen -t rsa
-
-Advanced Usage
---------------
-
-The flavor to deploy, the versions of upstream components to use can
-be configured by developers by setting certain environment variables.
-Below example deploys noha flavor using the latest of openstack-ansible
-master branch and stores logs in different location than what is configured.
-
-clone OPNFV Releng repository
-
-    git clone https://gerrit.opnfv.org/gerrit/releng.git
-
-change into directory where the sandbox script is located
-
-    cd releng/prototypes/xci
-
-set the sandbox flavor
-
-    export XCI_FLAVOR=noha
-
-set the version to use for openstack-ansible
-
-    export OPENSTACK_OSA_VERSION=master
-
-set where the logs should be stored
-
-    export LOG_PATH=/home/jenkins/xcilogs
-
-execute sandbox script
-
-    ./xci-deploy.sh
-
-===============
-User Variables
-===============
-
-All user variables can be set from command line by exporting them before
-executing the script. The current user variables can be seen from
-``releng/prototypes/xci/config/user-vars``.
-
-The variables can also be set directly within the file before executing
-the sandbox script.
-
-===============
-Pinned Versions
-===============
-
-As explained above, the users can pick and choose which versions to use. If
-you want to be on the safe side, you can use the pinned versions the sandbox
-provides. They can be seen from ``releng/prototypes/xci/config/pinned-versions``.
-
-How Pinned Versions are Determined
-----------------------------------
-
-OPNFV runs periodic jobs against upstream projects openstack/bifrost and
-openstack/ansible using latest on master and stable/ocata branches,
-continuously chasing the HEAD of corresponding branches.
-
-Once a working version is identified, the versions of the upstream components
-are then bumped in releng repo.
-
-==================
-XCI developer tips
-==================
-
-It is possible to run XCI in development mode, in order to test the
-latest changes. When deploying on this mode, the script will use the working
-directories for releng/bifrost/OSA, instead of cloning the whole repositories
-on each run.
-To enable it, you need to export the different DEV_PATH vars:
-
-- export OPNFV_RELENG_DEV_PATH=/opt/releng/
-- export OPENSTACK_BIFROST_DEV_PATH=/opt/bifrost/
-- export OPENSTACK_OSA_DEV_PATH=/opt/openstack-ansible/
-
-Please note the trailing slahses.
-
-This will cause the deployment to pick the development copies stored at the
-specified directories, and use them instead of cloning those on every run.
-
-===========================================
-Limitations, Known Issues, and Improvements
-===========================================
-
-The list can be seen using `this link <https://jira.opnfv.org/issues/?filter=11616>`_.
-
-=========
-Changelog
-=========
-
-Changelog can be seen using `this link <https://jira.opnfv.org/issues/?filter=11625>`_.
-
-=======
-Testing
-=======
-
-Sandbox is continuously tested by OPNFV CI to ensure the changes do not impact
-users. In fact, OPNFV CI itself uses the sandbox scripts to run daily platform
-verification jobs.
-
-=======
-Support
-=======
-
-OPNFV XCI issues are tracked on OPNFV JIRA Releng project. If you encounter
-and issue or identify a bug, please submit an issue to JIRA using
-`this link <https://jira.opnfv.org/projects/RELENG>_`.
-
-If you have questions or comments, you can ask them on ``#opnfv-pharos`` IRC
-channel on Freenode.
diff --git a/prototypes/xci/config/aio-vars b/prototypes/xci/config/aio-vars
deleted file mode 100755 (executable)
index f28ecff..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#-------------------------------------------------------------------------------
-# XCI Flavor Configuration
-#-------------------------------------------------------------------------------
-# You are free to modify parts of the configuration to fit into your environment.
-# But before doing that, please ensure you checked other flavors to see if one
-# them can be used instead, saving you some time.
-#-------------------------------------------------------------------------------
-
-#-------------------------------------------------------------------------------
-# Configure VM Nodes
-#-------------------------------------------------------------------------------
-export TEST_VM_NUM_NODES=1
-export TEST_VM_NODE_NAMES=opnfv
-export VM_DOMAIN_TYPE=kvm
-export VM_CPU=8
-export VM_DISK=80
-export VM_MEMORY_SIZE=8192
-export VM_DISK_CACHE=unsafe
diff --git a/prototypes/xci/config/env-vars b/prototypes/xci/config/env-vars
deleted file mode 100755 (executable)
index 9d4c782..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#-------------------------------------------------------------------------------
-# !!! Changing or overriding these will most likely break everything altogether !!!
-#    Please do not change these settings if you are not developing for XCI!
-#-------------------------------------------------------------------------------
-export OPNFV_RELENG_GIT_URL=https://gerrit.opnfv.org/gerrit/releng.git
-export OPENSTACK_BIFROST_GIT_URL=https://git.openstack.org/openstack/bifrost
-export OPENSTACK_OSA_GIT_URL=https://git.openstack.org/openstack/openstack-ansible
-export OPENSTACK_OSA_ETC_PATH=/etc/openstack_deploy
-export OPNFV_HOST_IP=192.168.122.2
-export XCI_FLAVOR_ANSIBLE_FILE_PATH=$OPNFV_RELENG_PATH/prototypes/xci/file/$XCI_FLAVOR
-export CI_LOOP=${CI_LOOP:-daily}
-export JOB_NAME=${JOB_NAME:-false}
-# TODO: this currently matches to bifrost ansible version
-# there is perhaps better way to do this
-export XCI_ANSIBLE_PIP_VERSION=2.1.5.0
-export ANSIBLE_HOST_KEY_CHECKING=False
-export DISTRO=${DISTRO:-ubuntu}
-export DIB_OS_RELEASE=${DIB_OS_RELEASE:-xenial}
-export DIB_OS_ELEMENT=${DIB_OS_ELEMENT:-ubuntu-minimal}
-export DIB_OS_PACKAGES=${DIB_OS_PACKAGES:-"vlan,vim,less,bridge-utils,sudo,language-pack-en,iputils-ping,rsyslog,curl,python,debootstrap,ifenslave,ifenslave-2.6,lsof,lvm2,tcpdump,nfs-kernel-server,chrony,iptables"}
-export EXTRA_DIB_ELEMENTS=${EXTRA_DIB_ELEMENTS:-"openssh-server"}
diff --git a/prototypes/xci/config/ha-vars b/prototypes/xci/config/ha-vars
deleted file mode 100755 (executable)
index 1ba4589..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#-------------------------------------------------------------------------------
-# XCI Flavor Configuration
-#-------------------------------------------------------------------------------
-# You are free to modify parts of the configuration to fit into your environment.
-# But before doing that, please ensure you checked other flavors to see if one
-# them can be used instead, saving you some time.
-#-------------------------------------------------------------------------------
-
-#-------------------------------------------------------------------------------
-# Configure VM Nodes
-#-------------------------------------------------------------------------------
-export TEST_VM_NUM_NODES=6
-export TEST_VM_NODE_NAMES="opnfv controller00 controller01 controller02 compute00 compute01"
-export VM_DOMAIN_TYPE=kvm
-export VM_CPU=8
-export VM_DISK=80
-export VM_MEMORY_SIZE=16384
-export VM_DISK_CACHE=unsafe
diff --git a/prototypes/xci/config/mini-vars b/prototypes/xci/config/mini-vars
deleted file mode 100755 (executable)
index 8f1e83c..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#-------------------------------------------------------------------------------
-# XCI Flavor Configuration
-#-------------------------------------------------------------------------------
-# You are free to modify parts of the configuration to fit into your environment.
-# But before doing that, please ensure you checked other flavors to see if one
-# them can be used instead, saving you some time.
-#-------------------------------------------------------------------------------
-
-#-------------------------------------------------------------------------------
-# Configure VM Nodes
-#-------------------------------------------------------------------------------
-export TEST_VM_NUM_NODES=3
-export TEST_VM_NODE_NAMES="opnfv controller00 compute00"
-export VM_DOMAIN_TYPE=kvm
-export VM_CPU=8
-export VM_DISK=80
-export VM_MEMORY_SIZE=12288
-export VM_DISK_CACHE=unsafe
diff --git a/prototypes/xci/config/noha-vars b/prototypes/xci/config/noha-vars
deleted file mode 100755 (executable)
index 935becb..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#-------------------------------------------------------------------------------
-# XCI Flavor Configuration
-#-------------------------------------------------------------------------------
-# You are free to modify parts of the configuration to fit into your environment.
-# But before doing that, please ensure you checked other flavors to see if one
-# them can be used instead, saving you some time.
-#-------------------------------------------------------------------------------
-
-#-------------------------------------------------------------------------------
-# Configure VM Nodes
-#-------------------------------------------------------------------------------
-export TEST_VM_NUM_NODES=4
-export TEST_VM_NODE_NAMES="opnfv controller00 compute00 compute01"
-export VM_DOMAIN_TYPE=kvm
-export VM_CPU=8
-export VM_DISK=80
-export VM_MEMORY_SIZE=12288
-export VM_DISK_CACHE=unsafe
diff --git a/prototypes/xci/config/pinned-versions b/prototypes/xci/config/pinned-versions
deleted file mode 100755 (executable)
index 5817860..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#-------------------------------------------------------------------------------
-# Pinned Component Versions
-#-------------------------------------------------------------------------------
-# You are free to override these versions in user-vars to experiment with
-# different branches or with different commits but be aware that things might
-# not work as expected. You can set the versions you want to use before running
-# the main script on your shell as shown on the examples below.
-#
-# It is important to be consistent between branches you use for OpenStack
-# projects OPNFV XCI uses.
-#
-# Examples:
-#   export OPENSTACK_BIFROST_VERSION="stable/ocata"
-#   export OPENSTACK_OSA_VERSION="stable/ocata"
-# or
-#   export OPENSTACK_BIFROST_VERSION="master"
-#   export OPENSTACK_OSA_VERSION="master"
-# or
-#   export OPENSTACK_BIFROST_VERSION="a87f7ce6c8725b3bbffec7b2efa1e466796848a9"
-#   export OPENSTACK_OSA_VERSION="4713cf45e11b4ebca9fbed25d1389854602213d8"
-#-------------------------------------------------------------------------------
-# use releng from master until the development work with the sandbox is complete
-export OPNFV_RELENG_VERSION="master"
-# HEAD of bifrost "master" as of 29.06.2017
-export OPENSTACK_BIFROST_VERSION=${OPENSTACK_BIFROST_VERSION:-"7c9bb5e07c6bc3b42c9a9e8457e5eef511075b38"}
-# HEAD of osa "master" as of 29.06.2017
-export OPENSTACK_OSA_VERSION=${OPENSTACK_OSA_VERSION:-"0648818c64239b534d00db381c4609f28e40bda9"}
diff --git a/prototypes/xci/config/user-vars b/prototypes/xci/config/user-vars
deleted file mode 100755 (executable)
index fd11a58..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#-------------------------------------------------------------------------------
-# Set Deployment Flavor
-#-------------------------------------------------------------------------------
-# OPNFV XCI currently supports 4 different types of flavors:
-#   - all in one (aio): 1 opnfv VM which acts as controller and compute node
-#   - mini: 3 VMs, 1 opnfv VM deployment host, 1 controller, and 1 compute nodes
-#   - noha: 4 VMs, 1 opnfv VM deployment host, 1 controller, and 2 compute nodes
-#   - ha: 6 VMs, 1 opnfv VM deployment host, 3 controllers, and 2 compute nodes
-#
-# Apart from having different number of nodes, CPU, RAM, and disk allocations
-# also differ from each other. Please take a look at the env-vars files for
-# each of these flavors.
-#
-# Examples:
-#   export XCI_FLAVOR="aio"
-# or
-#   export XCI_FLAVOR="mini"
-# or
-#   export XCI_FLAVOR="noha"
-# or
-#   export XCI_FLAVOR="ha"
-#-------------------------------------------------------------------------------
-export XCI_FLAVOR=${XCI_FLAVOR:-aio}
-
-#-------------------------------------------------------------------------------
-# Set Paths to where git repositories of XCI Components will be cloned
-#-------------------------------------------------------------------------------
-# OPNFV XCI Sandbox is not verified to be used as non-root user as of yet so
-# changing these paths might break things.
-#-------------------------------------------------------------------------------
-export XCI_DEVEL_ROOT=${XCI_DEVEL_ROOT:-"/tmp/.xci-deploy-env"}
-export OPNFV_RELENG_PATH="${XCI_DEVEL_ROOT}/releng"
-export OPENSTACK_BIFROST_PATH="${XCI_DEVEL_ROOT}/bifrost"
-export OPENSTACK_OSA_PATH="${XCI_DEVEL_ROOT}/openstack-ansible"
-export OPNFV_SSH_HOST_KEYS_PATH="${XCI_DEVEL_ROOT}/ssh_host_keys"
-
-#-------------------------------------------------------------------------------
-# Set the playbook to use for OpenStack deployment
-#-------------------------------------------------------------------------------
-# The variable can be overriden in order to install additional OpenStack services
-# supported by OpenStack Ansible or exclude certain OpenStack services.
-#-------------------------------------------------------------------------------
-export OPNFV_OSA_PLAYBOOK=${OPNFV_OSA_PLAYBOOK:-"$OPENSTACK_OSA_PATH/playbooks/setup-openstack.yml"}
-
-#-------------------------------------------------------------------------------
-# Configure some other stuff
-#-------------------------------------------------------------------------------
-# Set the verbosity for ansible
-#
-# Examples:
-#   ANSIBLE_VERBOSITY="-v"
-# or
-#   ANSIBLE_VERBOSITY="-vvvv"
-export ANSIBLE_VERBOSITY=${ANSIBLE_VERBOSITY-""}
-export LOG_PATH=${LOG_PATH:-${XCI_DEVEL_ROOT}/opnfv/logs}
-export RUN_TEMPEST=${RUN_TEMPEST:-false}
-# Set this to to true to force XCI to re-create the target OS images
-export CLEAN_DIB_IMAGES=${CLEAN_DIB_IMAGES:-false}
-# Set this to a full path pointing to extra config files (containing
-# group_vars/all)
-export XCI_EXTRA_VARS_PATH=${XCI_EXTRA_VARS_PATH:-""}
diff --git a/prototypes/xci/docs/developer-guide.rst b/prototypes/xci/docs/developer-guide.rst
deleted file mode 100644 (file)
index 9a07b12..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#########################
-OPNFV XCI Developer Guide
-#########################
-
-This document will contain details about the XCI and how things are put
-together in order to support different flavors and different distros in future.
-
-Document is for anyone who will
-
-- do hands on development with XCI such as new features to XCI itself or
-  bugfixes
-- integrate new features
-- want to know what is going on behind the scenes
-
-It will also have guidance regarding how to develop for the sandbox.
-
-If you are looking for User's Guide, please check README.rst in the root of
-xci folder or take a look at
-`Wiki <https://wiki.opnfv.org/display/INF/OpenStack>`_.
-
-===================================
-Components of XCI Developer Sandbox
-===================================
-
-TBD
-
-=============
-Detailed Flow
-=============
-
-TBD
diff --git a/prototypes/xci/file/aio/configure-opnfvhost.yml b/prototypes/xci/file/aio/configure-opnfvhost.yml
deleted file mode 100644 (file)
index 5c66d40..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- hosts: opnfv
-  remote_user: root
-  vars_files:
-  vars_files:
-    - ../var/opnfv.yml
-  roles:
-    - role: remove-folders
-    - { role: clone-repository, project: "openstack/openstack-ansible", repo: "{{ OPENSTACK_OSA_GIT_URL }}", dest: "{{ OPENSTACK_OSA_PATH }}", version: "{{ OPENSTACK_OSA_VERSION }}" }
-  tasks:
-    - name: bootstrap ansible on opnfv host
-      command: "/bin/bash ./scripts/bootstrap-ansible.sh"
-      args:
-        chdir: "{{OPENSTACK_OSA_PATH}}"
-    - name: bootstrap opnfv host as aio
-      command: "/bin/bash ./scripts/bootstrap-aio.sh"
-      args:
-        chdir: "{{OPENSTACK_OSA_PATH}}"
-    - name: install OpenStack on opnfv host - this command doesn't log anything to console
-      command: "/bin/bash ./scripts/run-playbooks.sh"
-      args:
-        chdir: "{{OPENSTACK_OSA_PATH}}"
diff --git a/prototypes/xci/file/aio/flavor-vars.yml b/prototypes/xci/file/aio/flavor-vars.yml
deleted file mode 100644 (file)
index 6ac1e0f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
----
-# this file is added intentionally in order to simplify putting files in place
-# in future, it might contain vars specific to this flavor
diff --git a/prototypes/xci/file/aio/inventory b/prototypes/xci/file/aio/inventory
deleted file mode 100644 (file)
index 9a3dd9e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[opnfv]
-opnfv ansible_ssh_host=192.168.122.2
diff --git a/prototypes/xci/file/ansible-role-requirements.yml b/prototypes/xci/file/ansible-role-requirements.yml
deleted file mode 100644 (file)
index 57e0bb8..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-# these versions are extracted based on the osa commit 0648818c64239b534d00db381c4609f28e40bda9 on 2017-06-27T22:02:17+00:00
-# https://review.openstack.org/gitweb?p=openstack/openstack-ansible.git;a=commit;h=0648818c64239b534d00db381c4609f28e40bda9
-- name: ansible-hardening
-  scm: git
-  src: https://git.openstack.org/openstack/ansible-hardening
-  version: f422da8599c6d8f64ebfefbf0a0aa711ea1f9569
-- name: apt_package_pinning
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-apt_package_pinning
-  version: 4afe664efb5a2385a1d7071f68bc9001f16c0f41
-- name: pip_install
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-pip_install
-  version: 348995b85f91f796b28656459474fb3935be737c
-- name: galera_client
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-galera_client
-  version: 2055ebf1582a15c2b2a73985485be15884c9b2d3
-- name: galera_server
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-galera_server
-  version: 78a1259a10a5be95ab7d6ba3e8f2961805ae3a5b
-- name: ceph_client
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-ceph_client
-  version: aa3b0d959464f9362aaf29d6cf6225e1d4e302be
-- name: haproxy_server
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-haproxy_server
-  version: f8bc5c6129c0d50ac3355c82560fbf22ee32479b
-- name: keepalived
-  scm: git
-  src: https://github.com/evrardjp/ansible-keepalived
-  version: 3.0.1
-- name: lxc_container_create
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-lxc_container_create
-  version: 1eab03452885f0a34cb78f54e3bcf5824abc012e
-- name: lxc_hosts
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-lxc_hosts
-  version: f0b8782c03dde4dd65e70d8b03afc26a30c74f37
-- name: memcached_server
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-memcached_server
-  version: 6924e7d44d6e36cbe45507e43ef82af6ac0ae125
-- name: openstack_hosts
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-openstack_hosts
-  version: d68b1dd8fc5ef18c78172d4e9fa3ca01d7473dcf
-- name: os_keystone
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_keystone
-  version: 0cafcc150da10a01ee0b4543167fdc88b9b91a85
-- name: openstack_openrc
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-openstack_openrc
-  version: 18b7f31a19c4c9bc95abc07a83c9ba866eff538d
-- name: os_aodh
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_aodh
-  version: 5bebd5a18aa7469803f26fb41df62495730afde3
-- name: os_barbican
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_barbican
-  version: fc95936f9375c3e9eab708b356e760e3eeb785d7
-- name: os_ceilometer
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_ceilometer
-  version: daf94c5d1a009abb111b5ff7dea8b4f50473b227
-- name: os_cinder
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_cinder
-  version: d0c46f29d7bb02139a14ad46869ce411e80874d9
-- name: os_glance
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_glance
-  version: a1e3588769e6d17b074398f0ef2675f34438b73b
-- name: os_gnocchi
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_gnocchi
-  version: f79b0f6e1db40b59390b7e40a90792e72afe55e6
-- name: os_heat
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_heat
-  version: 7a5b703b35f36a5a63ce9934ef585c8967e9de5a
-- name: os_horizon
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_horizon
-  version: cb4a27da79ad67b2826f637927514e0829c23c0f
-- name: os_ironic
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_ironic
-  version: e5c24e40b0d08d8bc7b4641679a8731c2b2aca29
-- name: os_magnum
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_magnum
-  version: 3eeb33db25db48f04e496a3ee47323fffe2af864
-- name: os_trove
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_trove
-  version: 0cf74c1a917b07e557411ca1c1376491c97aa0a9
-- name: os_neutron
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_neutron
-  version: 280788b20099532c13042966defcbcbf5d5dd994
-- name: os_nova
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_nova
-  version: 031b386bdd29f895203a3d053c1dabba66cfeeb0
-- name: os_rally
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_rally
-  version: 9125458265088eb8622f28df57f640509546a6d4
-- name: os_sahara
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_sahara
-  version: 433d624b0ddb0d2778f014a175064572e15ea462
-- name: os_swift
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_swift
-  version: 3b91c62e1de6e0d852476e3b74e39b7a55d77ec9
-- name: os_tempest
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_tempest
-  version: 692209da1fdab6014e13e65be27ffb9b8c8578bb
-- name: plugins
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-plugins
-  version: 8685a0ba38b7f534dd4db971da6d54b495c79169
-- name: rabbitmq_server
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-rabbitmq_server
-  version: 50bffbf8f114c8100ec5e86ebac9baba5c4f233d
-- name: repo_build
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-repo_build
-  version: 9ce713e9762650e1041ba7d9ad3c207a0c65d0c4
-- name: repo_server
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-repo_server
-  version: 275124b643d6e6a9c92d65be7a7f309fe6f0c6dc
-- name: rsyslog_client
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-rsyslog_client
-  version: da0090d48b166e0ffe83c35483572e358a29d523
-- name: rsyslog_server
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-rsyslog_server
-  version: 0f4b5ac0e7a170bd9811875965b781d447a5517a
-- name: sshd
-  scm: git
-  src: https://github.com/willshersystems/ansible-sshd
-  version: 0.5.1
-- name: bird
-  scm: git
-  src: https://github.com/logan2211/ansible-bird
-  version: '1.2'
-- name: etcd
-  scm: git
-  src: https://github.com/logan2211/ansible-etcd
-  version: '1.2'
-- name: unbound
-  scm: git
-  src: https://github.com/logan2211/ansible-unbound
-  version: '1.4'
-- name: resolvconf
-  scm: git
-  src: https://github.com/logan2211/ansible-resolvconf
-  version: '1.2'
-- name: os_designate
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_designate
-  version: cc9760d0a08083c1168999422ccefa0d56ead093
-- name: ceph.ceph-common
-  scm: git
-  src: https://github.com/ceph/ansible-ceph-common
-  version: v2.2.9
-- name: ceph.ceph-docker-common
-  scm: git
-  src: https://github.com/ceph/ansible-ceph-docker-common
-  version: ca86fd0ef6d24aa2c750a625acdcb8012c374aa0
-- name: ceph-mon
-  scm: git
-  src: https://github.com/ceph/ansible-ceph-mon
-  version: v2.2.9
-- name: ceph-osd
-  scm: git
-  src: https://github.com/ceph/ansible-ceph-osd
-  version: v2.2.9
-- name: os_octavia
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_octavia
-  version: 48ff9a634a3ea34c6811ebc10057708dc23ed76e
-- name: os_molteniron
-  scm: git
-  src: https://git.openstack.org/openstack/openstack-ansible-os_molteniron
-  version: 0de6fe5251b54881ab3eb8bf0a8d694dd4362430
diff --git a/prototypes/xci/file/cinder.yml b/prototypes/xci/file/cinder.yml
deleted file mode 100644 (file)
index e40b392..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
----
-# This file contains an example to show how to set
-# the cinder-volume service to run in a container.
-#
-# Important note:
-# When using LVM or any iSCSI-based cinder backends, such as NetApp with
-# iSCSI protocol, the cinder-volume service *must* run on metal.
-# Reference: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1226855
-
-container_skel:
-  cinder_volumes_container:
-    properties:
-      is_metal: false
diff --git a/prototypes/xci/file/ha/flavor-vars.yml b/prototypes/xci/file/ha/flavor-vars.yml
deleted file mode 100644 (file)
index 167502c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
----
-host_info: {
-    'opnfv': {
-        'VLAN_IP': '192.168.122.2',
-        'MGMT_IP': '172.29.236.10',
-        'VXLAN_IP': '172.29.240.10',
-        'STORAGE_IP': '172.29.244.10'
-    },
-    'controller00': {
-        'VLAN_IP': '192.168.122.3',
-        'MGMT_IP': '172.29.236.11',
-        'VXLAN_IP': '172.29.240.11',
-        'STORAGE_IP': '172.29.244.11'
-    },
-    'controller01': {
-        'VLAN_IP': '192.168.122.4',
-        'MGMT_IP': '172.29.236.12',
-        'VXLAN_IP': '172.29.240.12',
-        'STORAGE_IP': '172.29.244.12'
-    },
-    'controller02': {
-        'VLAN_IP': '192.168.122.5',
-        'MGMT_IP': '172.29.236.13',
-        'VXLAN_IP': '172.29.240.13',
-        'STORAGE_IP': '172.29.244.13'
-    },
-    'compute00': {
-        'VLAN_IP': '192.168.122.6',
-        'MGMT_IP': '172.29.236.14',
-        'VXLAN_IP': '172.29.240.14',
-        'STORAGE_IP': '172.29.244.14'
-    },
-    'compute01': {
-        'VLAN_IP': '192.168.122.7',
-        'MGMT_IP': '172.29.236.15',
-        'VXLAN_IP': '172.29.240.15',
-        'STORAGE_IP': '172.29.244.15'
-    }
-}
diff --git a/prototypes/xci/file/ha/inventory b/prototypes/xci/file/ha/inventory
deleted file mode 100644 (file)
index 94b1d07..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-[opnfv]
-opnfv ansible_ssh_host=192.168.122.2
-
-[controller]
-controller00 ansible_ssh_host=192.168.122.3
-controller01 ansible_ssh_host=192.168.122.4
-controller02 ansible_ssh_host=192.168.122.5
-
-[compute]
-compute00 ansible_ssh_host=192.168.122.6
-compute01 ansible_ssh_host=192.168.122.7
diff --git a/prototypes/xci/file/ha/openstack_user_config.yml b/prototypes/xci/file/ha/openstack_user_config.yml
deleted file mode 100644 (file)
index 09fb734..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
----
-cidr_networks:
-  container: 172.29.236.0/22
-  tunnel: 172.29.240.0/22
-  storage: 172.29.244.0/22
-
-used_ips:
-  - "172.29.236.1,172.29.236.50"
-  - "172.29.240.1,172.29.240.50"
-  - "172.29.244.1,172.29.244.50"
-  - "172.29.248.1,172.29.248.50"
-
-global_overrides:
-  internal_lb_vip_address: 172.29.236.222
-  external_lb_vip_address: 192.168.122.220
-  tunnel_bridge: "br-vxlan"
-  management_bridge: "br-mgmt"
-  provider_networks:
-    - network:
-        container_bridge: "br-mgmt"
-        container_type: "veth"
-        container_interface: "eth1"
-        ip_from_q: "container"
-        type: "raw"
-        group_binds:
-          - all_containers
-          - hosts
-        is_container_address: true
-        is_ssh_address: true
-    - network:
-        container_bridge: "br-vxlan"
-        container_type: "veth"
-        container_interface: "eth10"
-        ip_from_q: "tunnel"
-        type: "vxlan"
-        range: "1:1000"
-        net_name: "vxlan"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-vlan"
-        container_type: "veth"
-        container_interface: "eth12"
-        host_bind_override: "eth12"
-        type: "flat"
-        net_name: "flat"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-vlan"
-        container_type: "veth"
-        container_interface: "eth11"
-        type: "vlan"
-        range: "1:1"
-        net_name: "vlan"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-storage"
-        container_type: "veth"
-        container_interface: "eth2"
-        ip_from_q: "storage"
-        type: "raw"
-        group_binds:
-          - glance_api
-          - cinder_api
-          - cinder_volume
-          - nova_compute
-
-# ##
-# ## Infrastructure
-# ##
-
-# galera, memcache, rabbitmq, utility
-shared-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# repository (apt cache, python packages, etc)
-repo-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# load balancer
-# Ideally the load balancer should not use the Infrastructure hosts.
-# Dedicated hardware is best for improved performance and security.
-haproxy_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# rsyslog server
-# log_hosts:
-# log1:
-#  ip: 172.29.236.14
-
-# ##
-# ## OpenStack
-# ##
-
-# keystone
-identity_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# cinder api services
-storage-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# glance
-# The settings here are repeated for each infra host.
-# They could instead be applied as global settings in
-# user_variables, but are left here to illustrate that
-# each container could have different storage targets.
-image_hosts:
-  controller00:
-    ip: 172.29.236.11
-    container_vars:
-      limit_container_types: glance
-      glance_nfs_client:
-        - server: "172.29.244.14"
-          remote_path: "/images"
-          local_path: "/var/lib/glance/images"
-          type: "nfs"
-          options: "_netdev,auto"
-  controller01:
-    ip: 172.29.236.12
-    container_vars:
-      limit_container_types: glance
-      glance_nfs_client:
-        - server: "172.29.244.14"
-          remote_path: "/images"
-          local_path: "/var/lib/glance/images"
-          type: "nfs"
-          options: "_netdev,auto"
-  controller02:
-    ip: 172.29.236.13
-    container_vars:
-      limit_container_types: glance
-      glance_nfs_client:
-        - server: "172.29.244.14"
-          remote_path: "/images"
-          local_path: "/var/lib/glance/images"
-          type: "nfs"
-          options: "_netdev,auto"
-
-# nova api, conductor, etc services
-compute-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# heat
-orchestration_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# horizon
-dashboard_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# neutron server, agents (L3, etc)
-network_hosts:
-  controller00:
-    ip: 172.29.236.11
-  controller01:
-    ip: 172.29.236.12
-  controller02:
-    ip: 172.29.236.13
-
-# nova hypervisors
-compute_hosts:
-  compute00:
-    ip: 172.29.236.14
-  compute01:
-    ip: 172.29.236.15
-
-# cinder volume hosts (NFS-backed)
-# The settings here are repeated for each infra host.
-# They could instead be applied as global settings in
-# user_variables, but are left here to illustrate that
-# each container could have different storage targets.
-storage_hosts:
-  controller00:
-    ip: 172.29.236.11
-    container_vars:
-      cinder_backends:
-        limit_container_types: cinder_volume
-        nfs_volume:
-          volume_backend_name: NFS_VOLUME1
-          volume_driver: cinder.volume.drivers.nfs.NfsDriver
-          nfs_mount_options: "rsize=65535,wsize=65535,timeo=1200,actimeo=120"
-          nfs_shares_config: /etc/cinder/nfs_shares
-          shares:
-            - ip: "172.29.244.14"
-              share: "/volumes"
-  controller01:
-    ip: 172.29.236.12
-    container_vars:
-      cinder_backends:
-        limit_container_types: cinder_volume
-        nfs_volume:
-          volume_backend_name: NFS_VOLUME1
-          volume_driver: cinder.volume.drivers.nfs.NfsDriver
-          nfs_mount_options: "rsize=65535,wsize=65535,timeo=1200,actimeo=120"
-          nfs_shares_config: /etc/cinder/nfs_shares
-          shares:
-            - ip: "172.29.244.14"
-              share: "/volumes"
-  controller02:
-    ip: 172.29.236.13
-    container_vars:
-      cinder_backends:
-        limit_container_types: cinder_volume
-        nfs_volume:
-          volume_backend_name: NFS_VOLUME1
-          volume_driver: cinder.volume.drivers.nfs.NfsDriver
-          nfs_mount_options: "rsize=65535,wsize=65535,timeo=1200,actimeo=120"
-          nfs_shares_config: /etc/cinder/nfs_shares
-          shares:
-            - ip: "172.29.244.14"
-              share: "/volumes"
diff --git a/prototypes/xci/file/ha/user_variables.yml b/prototypes/xci/file/ha/user_variables.yml
deleted file mode 100644 (file)
index 094cc8c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
----
-# Copyright 2014, Rackspace US, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# ##
-# ## This file contains commonly used overrides for convenience. Please inspect
-# ## the defaults for each role to find additional override options.
-# ##
-
-# # Debug and Verbose options.
-debug: false
-
-haproxy_keepalived_external_vip_cidr: "192.168.122.220/32"
-haproxy_keepalived_internal_vip_cidr: "172.29.236.222/32"
-haproxy_keepalived_external_interface: br-vlan
-haproxy_keepalived_internal_interface: br-mgmt
-gnocchi_db_sync_options: ""
diff --git a/prototypes/xci/file/install-ansible.sh b/prototypes/xci/file/install-ansible.sh
deleted file mode 100644 (file)
index 67a49b3..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/bin/bash
-# NOTE(hwoarang): Most parts of this this file were taken from the
-# bifrost repository (scripts/install-deps.sh). This script contains all
-# the necessary distro specific code to install ansible and it's dependencies.
-
-set -eu
-
-declare -A PKG_MAP
-
-CHECK_CMD_PKGS=(
-    libffi
-    libopenssl
-    net-tools
-    python-devel
-)
-
-# Check zypper before apt-get in case zypper-aptitude
-# is installed
-if [ -x '/usr/bin/zypper' ]; then
-    OS_FAMILY="Suse"
-    INSTALLER_CMD="sudo -H -E zypper install -y"
-    CHECK_CMD="zypper search --match-exact --installed"
-    PKG_MAP=(
-        [gcc]=gcc
-        [git]=git
-        [libffi]=libffi-devel
-        [libopenssl]=libopenssl-devel
-        [net-tools]=net-tools
-        [python]=python
-        [python-devel]=python-devel
-        [venv]=python-virtualenv
-        [wget]=wget
-    )
-    EXTRA_PKG_DEPS=( python-xml )
-    # NOTE (cinerama): we can't install python without removing this package
-    # if it exists
-    if $(${CHECK_CMD} patterns-openSUSE-minimal_base-conflicts &> /dev/null); then
-        sudo -H zypper remove -y patterns-openSUSE-minimal_base-conflicts
-    fi
-elif [ -x '/usr/bin/apt-get' ]; then
-    OS_FAMILY="Debian"
-    INSTALLER_CMD="sudo -H -E apt-get -y install"
-    CHECK_CMD="dpkg -l"
-    PKG_MAP=( [gcc]=gcc
-              [git]=git
-              [libffi]=libffi-dev
-              [libopenssl]=libssl-dev
-              [net-tools]=net-tools
-              [python]=python-minimal
-              [python-devel]=libpython-dev
-              [venv]=python-virtualenv
-              [wget]=wget
-            )
-    EXTRA_PKG_DEPS=()
-elif [ -x '/usr/bin/dnf' ] || [ -x '/usr/bin/yum' ]; then
-    OS_FAMILY="RedHat"
-    PKG_MANAGER=$(which dnf || which yum)
-    INSTALLER_CMD="sudo -H -E ${PKG_MANAGER} -y install"
-    CHECK_CMD="rpm -q"
-    PKG_MAP=(
-        [gcc]=gcc
-        [git]=git
-        [libffi]=libffi-devel
-        [libopenssl]=openssl-devel
-        [net-tools]=net-tools
-        [python]=python
-        [python-devel]=python-devel
-        [venv]=python-virtualenv
-        [wget]=wget
-    )
-    EXTRA_PKG_DEPS=()
-else
-    echo "ERROR: Supported package manager not found.  Supported: apt,yum,zypper"
-fi
-
-if ! $(python --version &>/dev/null); then
-    ${INSTALLER_CMD} ${PKG_MAP[python]}
-fi
-if ! $(gcc -v &>/dev/null); then
-    ${INSTALLER_CMD} ${PKG_MAP[gcc]}
-fi
-if ! $(git --version &>/dev/null); then
-    ${INSTALLER_CMD} ${PKG_MAP[git]}
-fi
-if ! $(wget --version &>/dev/null); then
-    ${INSTALLER_CMD} ${PKG_MAP[wget]}
-fi
-
-for pkg in ${CHECK_CMD_PKGS[@]}; do
-    if ! $(${CHECK_CMD} ${PKG_MAP[$pkg]} &>/dev/null); then
-        ${INSTALLER_CMD} ${PKG_MAP[$pkg]}
-    fi
-done
-
-if [ -n "${EXTRA_PKG_DEPS-}" ]; then
-    for pkg in ${EXTRA_PKG_DEPS}; do
-        if ! $(${CHECK_CMD} ${pkg} &>/dev/null); then
-            ${INSTALLER_CMD} ${pkg}
-        fi
-    done
-fi
-
-# If we're using a venv, we need to work around sudo not
-# keeping the path even with -E.
-PYTHON=$(which python)
-
-# To install python packages, we need pip.
-#
-# We can't use the apt packaged version of pip since
-# older versions of pip are incompatible with
-# requests, one of our indirect dependencies (bug 1459947).
-#
-# Note(cinerama): We use pip to install an updated pip plus our
-# other python requirements. pip breakages can seriously impact us,
-# so we've chosen to install/upgrade pip here rather than in
-# requirements (which are synced automatically from the global ones)
-# so we can quickly and easily adjust version parameters.
-# See bug 1536627.
-#
-# Note(cinerama): If pip is linked to pip3, the rest of the install
-# won't work. Remove the alternatives. This is due to ansible's
-# python 2.x requirement.
-if [[ $(readlink -f /etc/alternatives/pip) =~ "pip3" ]]; then
-    sudo -H update-alternatives --remove pip $(readlink -f /etc/alternatives/pip)
-fi
-
-if ! which pip; then
-    wget -O /tmp/get-pip.py https://bootstrap.pypa.io/get-pip.py
-    sudo -H -E ${PYTHON} /tmp/get-pip.py
-fi
-
-PIP=$(which pip)
-
-${PIP} install --user "pip>6.0"
-
-${PIP} install --user --upgrade ansible==$XCI_ANSIBLE_PIP_VERSION
diff --git a/prototypes/xci/file/mini/flavor-vars.yml b/prototypes/xci/file/mini/flavor-vars.yml
deleted file mode 100644 (file)
index 0d446ba..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
----
-host_info: {
-    'opnfv': {
-        'VLAN_IP': '192.168.122.2',
-        'MGMT_IP': '172.29.236.10',
-        'VXLAN_IP': '172.29.240.10',
-        'STORAGE_IP': '172.29.244.10'
-    },
-    'controller00': {
-        'VLAN_IP': '192.168.122.3',
-        'MGMT_IP': '172.29.236.11',
-        'VXLAN_IP': '172.29.240.11',
-        'STORAGE_IP': '172.29.244.11'
-    },
-    'compute00': {
-        'VLAN_IP': '192.168.122.4',
-        'MGMT_IP': '172.29.236.12',
-        'VXLAN_IP': '172.29.240.12',
-        'STORAGE_IP': '172.29.244.12'
-    },
-}
diff --git a/prototypes/xci/file/mini/inventory b/prototypes/xci/file/mini/inventory
deleted file mode 100644 (file)
index eb73e5e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-[opnfv]
-opnfv ansible_ssh_host=192.168.122.2
-
-[controller]
-controller00 ansible_ssh_host=192.168.122.3
-
-[compute]
-compute00 ansible_ssh_host=192.168.122.4
diff --git a/prototypes/xci/file/mini/openstack_user_config.yml b/prototypes/xci/file/mini/openstack_user_config.yml
deleted file mode 100644 (file)
index f9ccee2..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
----
-cidr_networks:
-  container: 172.29.236.0/22
-  tunnel: 172.29.240.0/22
-  storage: 172.29.244.0/22
-
-used_ips:
-  - "172.29.236.1,172.29.236.50"
-  - "172.29.240.1,172.29.240.50"
-  - "172.29.244.1,172.29.244.50"
-  - "172.29.248.1,172.29.248.50"
-
-global_overrides:
-  internal_lb_vip_address: 172.29.236.11
-  external_lb_vip_address: 192.168.122.3
-  tunnel_bridge: "br-vxlan"
-  management_bridge: "br-mgmt"
-  provider_networks:
-    - network:
-        container_bridge: "br-mgmt"
-        container_type: "veth"
-        container_interface: "eth1"
-        ip_from_q: "container"
-        type: "raw"
-        group_binds:
-          - all_containers
-          - hosts
-        is_container_address: true
-        is_ssh_address: true
-    - network:
-        container_bridge: "br-vxlan"
-        container_type: "veth"
-        container_interface: "eth10"
-        ip_from_q: "tunnel"
-        type: "vxlan"
-        range: "1:1000"
-        net_name: "vxlan"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-vlan"
-        container_type: "veth"
-        container_interface: "eth12"
-        host_bind_override: "eth12"
-        type: "flat"
-        net_name: "flat"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-vlan"
-        container_type: "veth"
-        container_interface: "eth11"
-        type: "vlan"
-        range: "1:1"
-        net_name: "vlan"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-storage"
-        container_type: "veth"
-        container_interface: "eth2"
-        ip_from_q: "storage"
-        type: "raw"
-        group_binds:
-          - glance_api
-          - cinder_api
-          - cinder_volume
-          - nova_compute
-
-# ##
-# ## Infrastructure
-# ##
-
-# galera, memcache, rabbitmq, utility
-shared-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# repository (apt cache, python packages, etc)
-repo-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# load balancer
-# Ideally the load balancer should not use the Infrastructure hosts.
-# Dedicated hardware is best for improved performance and security.
-haproxy_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# rsyslog server
-# log_hosts:
-# log1:
-#  ip: 172.29.236.14
-
-# ##
-# ## OpenStack
-# ##
-
-# keystone
-identity_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# cinder api services
-storage-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# glance
-# The settings here are repeated for each infra host.
-# They could instead be applied as global settings in
-# user_variables, but are left here to illustrate that
-# each container could have different storage targets.
-image_hosts:
-  controller00:
-    ip: 172.29.236.11
-    container_vars:
-      limit_container_types: glance
-      glance_nfs_client:
-        - server: "172.29.244.12"
-          remote_path: "/images"
-          local_path: "/var/lib/glance/images"
-          type: "nfs"
-          options: "_netdev,auto"
-
-# nova api, conductor, etc services
-compute-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# heat
-orchestration_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# horizon
-dashboard_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# neutron server, agents (L3, etc)
-network_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# nova hypervisors
-compute_hosts:
-  compute00:
-    ip: 172.29.236.12
-
-# cinder volume hosts (NFS-backed)
-# The settings here are repeated for each infra host.
-# They could instead be applied as global settings in
-# user_variables, but are left here to illustrate that
-# each container could have different storage targets.
-storage_hosts:
-  controller00:
-    ip: 172.29.236.11
-    container_vars:
-      cinder_backends:
-        limit_container_types: cinder_volume
-        nfs_volume:
-          volume_backend_name: NFS_VOLUME1
-          volume_driver: cinder.volume.drivers.nfs.NfsDriver
-          nfs_mount_options: "rsize=65535,wsize=65535,timeo=1200,actimeo=120"
-          nfs_shares_config: /etc/cinder/nfs_shares
-          shares:
-            - ip: "172.29.244.12"
-              share: "/volumes"
diff --git a/prototypes/xci/file/mini/user_variables.yml b/prototypes/xci/file/mini/user_variables.yml
deleted file mode 100644 (file)
index 7a0b806..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
----
-# Copyright 2014, Rackspace US, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# ##
-# ## This file contains commonly used overrides for convenience. Please inspect
-# ## the defaults for each role to find additional override options.
-# ##
-
-# # Debug and Verbose options.
-debug: false
-
-haproxy_keepalived_external_vip_cidr: "192.168.122.3/32"
-haproxy_keepalived_internal_vip_cidr: "172.29.236.11/32"
-haproxy_keepalived_external_interface: br-vlan
-haproxy_keepalived_internal_interface: br-mgmt
-gnocchi_db_sync_options: ""
diff --git a/prototypes/xci/file/noha/flavor-vars.yml b/prototypes/xci/file/noha/flavor-vars.yml
deleted file mode 100644 (file)
index 3c69a34..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
----
-host_info: {
-    'opnfv': {
-        'VLAN_IP': '192.168.122.2',
-        'MGMT_IP': '172.29.236.10',
-        'VXLAN_IP': '172.29.240.10',
-        'STORAGE_IP': '172.29.244.10'
-    },
-    'controller00': {
-        'VLAN_IP': '192.168.122.3',
-        'MGMT_IP': '172.29.236.11',
-        'VXLAN_IP': '172.29.240.11',
-        'STORAGE_IP': '172.29.244.11'
-    },
-    'compute00': {
-        'VLAN_IP': '192.168.122.4',
-        'MGMT_IP': '172.29.236.12',
-        'VXLAN_IP': '172.29.240.12',
-        'STORAGE_IP': '172.29.244.12'
-    },
-    'compute01': {
-        'VLAN_IP': '192.168.122.5',
-        'MGMT_IP': '172.29.236.13',
-        'VXLAN_IP': '172.29.240.13',
-        'STORAGE_IP': '172.29.244.13'
-    }
-}
diff --git a/prototypes/xci/file/noha/inventory b/prototypes/xci/file/noha/inventory
deleted file mode 100644 (file)
index b4f9f6d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[opnfv]
-opnfv ansible_ssh_host=192.168.122.2
-
-[controller]
-controller00 ansible_ssh_host=192.168.122.3
-
-[compute]
-compute00 ansible_ssh_host=192.168.122.4
-compute01 ansible_ssh_host=192.168.122.5
diff --git a/prototypes/xci/file/noha/openstack_user_config.yml b/prototypes/xci/file/noha/openstack_user_config.yml
deleted file mode 100644 (file)
index fb12655..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
----
-cidr_networks:
-  container: 172.29.236.0/22
-  tunnel: 172.29.240.0/22
-  storage: 172.29.244.0/22
-
-used_ips:
-  - "172.29.236.1,172.29.236.50"
-  - "172.29.240.1,172.29.240.50"
-  - "172.29.244.1,172.29.244.50"
-  - "172.29.248.1,172.29.248.50"
-
-global_overrides:
-  internal_lb_vip_address: 172.29.236.11
-  external_lb_vip_address: 192.168.122.3
-  tunnel_bridge: "br-vxlan"
-  management_bridge: "br-mgmt"
-  provider_networks:
-    - network:
-        container_bridge: "br-mgmt"
-        container_type: "veth"
-        container_interface: "eth1"
-        ip_from_q: "container"
-        type: "raw"
-        group_binds:
-          - all_containers
-          - hosts
-        is_container_address: true
-        is_ssh_address: true
-    - network:
-        container_bridge: "br-vxlan"
-        container_type: "veth"
-        container_interface: "eth10"
-        ip_from_q: "tunnel"
-        type: "vxlan"
-        range: "1:1000"
-        net_name: "vxlan"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-vlan"
-        container_type: "veth"
-        container_interface: "eth12"
-        host_bind_override: "eth12"
-        type: "flat"
-        net_name: "flat"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-vlan"
-        container_type: "veth"
-        container_interface: "eth11"
-        type: "vlan"
-        range: "1:1"
-        net_name: "vlan"
-        group_binds:
-          - neutron_linuxbridge_agent
-    - network:
-        container_bridge: "br-storage"
-        container_type: "veth"
-        container_interface: "eth2"
-        ip_from_q: "storage"
-        type: "raw"
-        group_binds:
-          - glance_api
-          - cinder_api
-          - cinder_volume
-          - nova_compute
-
-# ##
-# ## Infrastructure
-# ##
-
-# galera, memcache, rabbitmq, utility
-shared-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# repository (apt cache, python packages, etc)
-repo-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# load balancer
-# Ideally the load balancer should not use the Infrastructure hosts.
-# Dedicated hardware is best for improved performance and security.
-haproxy_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# rsyslog server
-# log_hosts:
-# log1:
-#  ip: 172.29.236.14
-
-# ##
-# ## OpenStack
-# ##
-
-# keystone
-identity_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# cinder api services
-storage-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# glance
-# The settings here are repeated for each infra host.
-# They could instead be applied as global settings in
-# user_variables, but are left here to illustrate that
-# each container could have different storage targets.
-image_hosts:
-  controller00:
-    ip: 172.29.236.11
-    container_vars:
-      limit_container_types: glance
-      glance_nfs_client:
-        - server: "172.29.244.12"
-          remote_path: "/images"
-          local_path: "/var/lib/glance/images"
-          type: "nfs"
-          options: "_netdev,auto"
-
-# nova api, conductor, etc services
-compute-infra_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# heat
-orchestration_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# horizon
-dashboard_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# neutron server, agents (L3, etc)
-network_hosts:
-  controller00:
-    ip: 172.29.236.11
-
-# nova hypervisors
-compute_hosts:
-  compute00:
-    ip: 172.29.236.12
-  compute01:
-    ip: 172.29.236.13
-
-# cinder volume hosts (NFS-backed)
-# The settings here are repeated for each infra host.
-# They could instead be applied as global settings in
-# user_variables, but are left here to illustrate that
-# each container could have different storage targets.
-storage_hosts:
-  controller00:
-    ip: 172.29.236.11
-    container_vars:
-      cinder_backends:
-        limit_container_types: cinder_volume
-        nfs_volume:
-          volume_backend_name: NFS_VOLUME1
-          volume_driver: cinder.volume.drivers.nfs.NfsDriver
-          nfs_mount_options: "rsize=65535,wsize=65535,timeo=1200,actimeo=120"
-          nfs_shares_config: /etc/cinder/nfs_shares
-          shares:
-            - ip: "172.29.244.12"
-              share: "/volumes"
diff --git a/prototypes/xci/file/noha/user_variables.yml b/prototypes/xci/file/noha/user_variables.yml
deleted file mode 100644 (file)
index 7a0b806..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
----
-# Copyright 2014, Rackspace US, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# ##
-# ## This file contains commonly used overrides for convenience. Please inspect
-# ## the defaults for each role to find additional override options.
-# ##
-
-# # Debug and Verbose options.
-debug: false
-
-haproxy_keepalived_external_vip_cidr: "192.168.122.3/32"
-haproxy_keepalived_internal_vip_cidr: "172.29.236.11/32"
-haproxy_keepalived_external_interface: br-vlan
-haproxy_keepalived_internal_interface: br-mgmt
-gnocchi_db_sync_options: ""
diff --git a/prototypes/xci/file/setup-openstack.yml b/prototypes/xci/file/setup-openstack.yml
deleted file mode 100644 (file)
index 415c489..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
----
-# Copyright 2014, Rackspace US, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-- include: os-keystone-install.yml
-- include: os-glance-install.yml
-- include: os-cinder-install.yml
-- include: os-nova-install.yml
-- include: os-neutron-install.yml
-- include: os-heat-install.yml
-- include: os-horizon-install.yml
-- include: os-swift-install.yml
-- include: os-ironic-install.yml
-- include: os-tempest-install.yml
diff --git a/prototypes/xci/playbooks/configure-localhost.yml b/prototypes/xci/playbooks/configure-localhost.yml
deleted file mode 100644 (file)
index b6d0fcc..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-- hosts: localhost
-  connection: local
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/opnfv.yml
-  roles:
-    - role: remove-folders
-    - { role: clone-repository, project: "opnfv/releng", repo: "{{ OPNFV_RELENG_GIT_URL }}", dest: "{{ OPNFV_RELENG_PATH }}", version: "{{ OPNFV_RELENG_VERSION }}" }
-
-- hosts: localhost
-  connection: local
-  gather_facts: false
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/opnfv.yml
-  tasks:
-    - name: Synchronize local development releng repository to XCI paths
-      synchronize:
-        src: "{{ OPNFV_RELENG_DEV_PATH }}"
-        dest: "{{ OPNFV_RELENG_PATH }}"
-        recursive: yes
-        delete: yes
-      when:
-        - OPNFV_RELENG_DEV_PATH != ""
-
-- hosts: localhost
-  connection: local
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/opnfv.yml
-  tasks:
-    - name:  create log directory {{LOG_PATH}}
-      file:
-        path: "{{LOG_PATH}}"
-        state: directory
-        recurse: no
-    # when the deployment is aio, we overwrite and use playbook, configure-opnfvhost.yml, since everything gets installed on opnfv host
-    - name: copy aio playbook
-      copy:
-        src: "{{XCI_FLAVOR_ANSIBLE_FILE_PATH}}/configure-opnfvhost.yml"
-        dest: "{{OPNFV_RELENG_PATH}}/prototypes/xci/playbooks"
-      when: XCI_FLAVOR == "aio"
-    - name: copy flavor inventory
-      copy:
-        src: "{{XCI_FLAVOR_ANSIBLE_FILE_PATH}}/inventory"
-        dest: "{{OPNFV_RELENG_PATH}}/prototypes/xci/playbooks"
-    - name: copy flavor vars
-      copy:
-        src: "{{XCI_FLAVOR_ANSIBLE_FILE_PATH}}/flavor-vars.yml"
-        dest: "{{OPNFV_RELENG_PATH}}/prototypes/xci/var"
diff --git a/prototypes/xci/playbooks/configure-opnfvhost.yml b/prototypes/xci/playbooks/configure-opnfvhost.yml
deleted file mode 100644 (file)
index 8656ff9..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-- hosts: opnfv
-  remote_user: root
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/flavor-vars.yml
-    - ../var/opnfv.yml
-  roles:
-    - role: remove-folders
-    - { role: clone-repository, project: "opnfv/releng", repo: "{{ OPNFV_RELENG_GIT_URL }}", dest: "{{ OPNFV_RELENG_PATH }}", version: "{{ OPNFV_RELENG_VERSION }}" }
-    - { role: clone-repository, project: "openstack/openstack-ansible", repo: "{{ OPENSTACK_OSA_GIT_URL }}", dest: "{{ OPENSTACK_OSA_PATH }}", version: "{{ OPENSTACK_OSA_VERSION }}" }
-
-- hosts: opnfv
-  remote_user: root
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/opnfv.yml
-  tasks:
-    - name: Synchronize local development releng repository to XCI paths
-      synchronize:
-        src: "{{ OPNFV_RELENG_DEV_PATH }}"
-        dest: "{{ OPNFV_RELENG_PATH }}"
-        recursive: yes
-        delete: yes
-      when:
-        - OPNFV_RELENG_DEV_PATH != ""
-    - name: Synchronize local development openstack-ansible repository to XCI paths
-      synchronize:
-        src: "{{ OPENSTACK_OSA_DEV_PATH }}"
-        dest: "{{ OPENSTACK_OSA_PATH }}"
-        recursive: yes
-        delete: yes
-      when:
-        - OPENSTACK_OSA_DEV_PATH != ""
-
-- hosts: opnfv
-  remote_user: root
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/flavor-vars.yml
-    - ../var/opnfv.yml
-  roles:
-    # TODO: this only works for ubuntu/xenial and need to be adjusted for other distros
-    - { role: configure-network, when: ansible_distribution_release == "xenial", src: "../template/opnfv.interface.j2", dest: "/etc/network/interfaces" }
-  tasks:
-    - name: generate SSH keys
-      shell: ssh-keygen -b 2048 -t rsa -f /root/.ssh/id_rsa -q -N ""
-      args:
-        creates: /root/.ssh/id_rsa
-    - name: ensure ssh key storage directory exists
-      file:
-        path: "{{ OPNFV_SSH_HOST_KEYS_PATH }}"
-        state: directory
-    - name: fetch public key
-      fetch: src="/root/.ssh/id_rsa.pub" dest="{{ OPNFV_SSH_HOST_KEYS_PATH }}"
-    - name: copy flavor inventory
-      shell: "/bin/cp -rf {{XCI_FLAVOR_ANSIBLE_FILE_PATH}}/inventory {{OPNFV_RELENG_PATH}}/prototypes/xci/playbooks"
-    - name: copy flavor vars
-      shell: "/bin/cp -rf {{XCI_FLAVOR_ANSIBLE_FILE_PATH}}/flavor-vars.yml {{OPNFV_RELENG_PATH}}/prototypes/xci/var"
-    - name: copy openstack_deploy
-      shell: "/bin/cp -rf {{OPENSTACK_OSA_PATH}}/etc/openstack_deploy {{OPENSTACK_OSA_ETC_PATH}}"
-    - name: copy openstack_user_config.yml
-      shell: "/bin/cp -rf {{XCI_FLAVOR_ANSIBLE_FILE_PATH}}/openstack_user_config.yml {{OPENSTACK_OSA_ETC_PATH}}"
-    - name: copy user_variables.yml
-      shell: "/bin/cp -rf {{XCI_FLAVOR_ANSIBLE_FILE_PATH}}/user_variables.yml {{OPENSTACK_OSA_ETC_PATH}}"
-    - name: copy cinder.yml
-      shell: "/bin/cp -rf {{OPNFV_RELENG_PATH}}/prototypes/xci/file/cinder.yml {{OPENSTACK_OSA_ETC_PATH}}/env.d"
-    # TODO: We need to get rid of this as soon as the issue is fixed upstream
-    - name: change the haproxy state from disable to enable
-      replace:
-        dest: "{{OPENSTACK_OSA_PATH}}/playbooks/os-keystone-install.yml"
-        regexp: '(\s+)haproxy_state: disabled'
-        replace: '\1haproxy_state: enabled'
-    - name: copy OPNFV OpenStack playbook
-      shell: "/bin/cp -rf {{OPNFV_RELENG_PATH}}/prototypes/xci/file/setup-openstack.yml {{OPENSTACK_OSA_PATH}}/playbooks"
-    - name: copy OPNFV role requirements
-      shell: "/bin/cp -rf {{OPNFV_RELENG_PATH}}/prototypes/xci/file/ansible-role-requirements.yml {{OPENSTACK_OSA_PATH}}"
-    - name: bootstrap ansible on opnfv host
-      command: "/bin/bash ./scripts/bootstrap-ansible.sh"
-      args:
-        chdir: "{{OPENSTACK_OSA_PATH}}"
-    - name: generate password token
-      command: "python pw-token-gen.py --file {{OPENSTACK_OSA_ETC_PATH}}/user_secrets.yml"
-      args:
-        chdir: "{{OPENSTACK_OSA_PATH}}/scripts"
-- hosts: localhost
-  remote_user: root
-  vars_files:
-    - ../var/opnfv.yml
-  tasks:
-    - name: Generate authorized_keys
-      shell: "/bin/cat {{ OPNFV_SSH_HOST_KEYS_PATH }}/opnfv/root/.ssh/id_rsa.pub >> ../file/authorized_keys"
-    - name: Append public keys to authorized_keys
-      shell: "/bin/cat {{ ansible_env.HOME }}/.ssh/id_rsa.pub >> ../file/authorized_keys"
diff --git a/prototypes/xci/playbooks/configure-targethosts.yml b/prototypes/xci/playbooks/configure-targethosts.yml
deleted file mode 100644 (file)
index 50da1f2..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
----
-- hosts: all
-  remote_user: root
-  tasks:
-    - name: add public key to host
-      copy:
-        src: ../file/authorized_keys
-        dest: /root/.ssh/authorized_keys
-
-- hosts: controller
-  remote_user: root
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/flavor-vars.yml
-  roles:
-    # TODO: this only works for ubuntu/xenial and need to be adjusted for other distros
-    - { role: configure-network, src: "../template/controller.interface.j2", dest: "/etc/network/interfaces" }
-    # we need to force sync time with ntp or the nodes will be out of sync timewise
-    - role: synchronize-time
-
-- hosts: compute
-  remote_user: root
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/flavor-vars.yml
-  roles:
-    # TODO: this only works for ubuntu/xenial and need to be adjusted for other distros
-    - { role: configure-network, src: "../template/compute.interface.j2", dest: "/etc/network/interfaces" }
-    # we need to force sync time with ntp or the nodes will be out of sync timewise
-    - role: synchronize-time
-
-- hosts: compute00
-  remote_user: root
-  # TODO: this role is for configuring NFS on xenial and adjustment needed for other distros
-  roles:
-    - role: configure-nfs
diff --git a/prototypes/xci/playbooks/inventory b/prototypes/xci/playbooks/inventory
deleted file mode 100644 (file)
index fd9af90..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-[opnfv]
-opnfv ansible_ssh_host=192.168.122.2
diff --git a/prototypes/xci/playbooks/provision-vm-nodes.yml b/prototypes/xci/playbooks/provision-vm-nodes.yml
deleted file mode 100644 (file)
index 92b5c55..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-- hosts: localhost
-  connection: local
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/opnfv.yml
-  roles:
-    # using these roles here ensures that we can reuse this playbook in different context
-    - role: remove-folders
-    - { role: clone-repository, project: "opnfv/releng", repo: "{{ OPNFV_RELENG_GIT_URL }}", dest: "{{ OPNFV_RELENG_PATH }}", version: "{{ OPNFV_RELENG_VERSION }}" }
-    - { role: clone-repository, project: "opnfv/bifrost", repo: "{{ OPENSTACK_BIFROST_GIT_URL }}", dest: "{{ OPENSTACK_BIFROST_PATH }}", version: "{{ OPENSTACK_BIFROST_VERSION }}" }
-
-- hosts: localhost
-  connection: local
-  gather_facts: false
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/opnfv.yml
-  tasks:
-    - name: Synchronize local development bifrost repository to XCI paths
-      # command module is much faster than the copy module
-      synchronize:
-        src: "{{ OPENSTACK_BIFROST_DEV_PATH }}"
-        dest: "{{ OPENSTACK_BIFROST_PATH }}"
-        recursive: yes
-        delete: yes
-      when:
-        - OPENSTACK_BIFROST_DEV_PATH != ""
-    - name: Synchronize local development releng repository to XCI paths
-      synchronize:
-        src: "{{ OPNFV_RELENG_DEV_PATH }}"
-        dest: "{{ OPNFV_RELENG_PATH }}"
-        recursive: yes
-        delete: yes
-      when:
-        - OPNFV_RELENG_DEV_PATH != ""
-    - name: Copy extra vars to releng and bifrost
-      synchronize:
-        src: "{{ XCI_EXTRA_VARS_PATH }}"
-        dest: "{{ item }}"
-      with_items:
-        - "{{ OPNFV_RELENG_PATH }}/prototypes/xci/playbooks"
-        - "{{ OPENSTACK_BIFROST_PATH }}/playbooks/inventory"
-      when:
-        - XCI_EXTRA_VARS_PATH != ""
-
-- hosts: localhost
-  connection: local
-  gather_facts: false
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/opnfv.yml
-  tasks:
-    - name: combine opnfv/releng and openstack/bifrost scripts/playbooks
-      copy:
-        src: "{{ OPNFV_RELENG_PATH }}/prototypes/bifrost/"
-        dest: "{{ OPENSTACK_BIFROST_PATH }}"
-
-- hosts: localhost
-  connection: local
-  become: yes
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/opnfv.yml
-  tasks:
-    - name: destroy VM nodes created by previous deployment
-      command: "/bin/bash ./scripts/destroy-env.sh"
-      args:
-        chdir: "{{ OPENSTACK_BIFROST_PATH }}"
-
-- hosts: localhost
-  connection: local
-  vars_files:
-    - ../var/{{ ansible_os_family }}.yml
-    - ../var/opnfv.yml
-  tasks:
-    - name: create and provision VM nodes for the flavor {{ XCI_FLAVOR }}
-      command: "/bin/bash ./scripts/bifrost-provision.sh"
-      args:
-        chdir: "{{ OPENSTACK_BIFROST_PATH }}"
diff --git a/prototypes/xci/playbooks/roles/clone-repository/tasks/main.yml b/prototypes/xci/playbooks/roles/clone-repository/tasks/main.yml
deleted file mode 100644 (file)
index 3f7e091..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-- name: clone "{{ project }}" and checkout "{{ version }}"
-  git:
-    repo: "{{ repo }}"
-    dest: "{{ dest }}"
-    version: "{{ version }}"
diff --git a/prototypes/xci/playbooks/roles/configure-network/tasks/main.yml b/prototypes/xci/playbooks/roles/configure-network/tasks/main.yml
deleted file mode 100644 (file)
index aafadf7..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-# TODO: this role needs to be adjusted for different distros
-- block:
-    - name: configure modules
-      lineinfile:
-        dest: /etc/modules
-        state: present
-        create: yes
-        line: "8021q"
-    - name: add modules
-      modprobe:
-        name: 8021q
-        state: present
-    - name: ensure glean rules are removed
-      file:
-        path: "/etc/udev/rules.d/99-glean.rules"
-        state: absent
-    - name: ensure interfaces.d folder is empty
-      shell: "/bin/rm -rf /etc/network/interfaces.d/*"
-    - name: ensure interfaces file is updated
-      template:
-        src: "{{ src }}"
-        dest: "{{ dest }}"
-    - name: restart network service
-      shell: "/sbin/ifconfig {{ interface }} 0 && /sbin/ifdown -a && /sbin/ifup -a"
-  when: ansible_distribution_release == "xenial"
diff --git a/prototypes/xci/playbooks/roles/configure-nfs/tasks/main.yml b/prototypes/xci/playbooks/roles/configure-nfs/tasks/main.yml
deleted file mode 100644 (file)
index c52da0b..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-# TODO: this is for xenial and needs to be adjusted for different distros
-- block:
-    - name: make NFS directories
-      file:
-        dest: "{{ item }}"
-        mode: 0777
-        state: directory
-      with_items:
-        - "/images"
-        - "/volumes"
-    - name: configure NFS service
-      lineinfile:
-        dest: /etc/services
-        state: present
-        create: yes
-        line: "{{ item }}"
-      with_items:
-        - "nfs        2049/tcp"
-        - "nfs        2049/udp"
-    - name: configure NFS exports
-      lineinfile:
-        dest: /etc/exports
-        state: present
-        create: yes
-        line: "{{ item }}"
-      with_items:
-        - "/images         *(rw,sync,no_subtree_check,no_root_squash)"
-        - "/volumes        *(rw,sync,no_subtree_check,no_root_squash)"
-    # TODO: the service name might be different on other distros and needs to be adjusted
-    - name: restart ubuntu xenial NFS service
-      service:
-        name: nfs-kernel-server
-        state: restarted
-  when: ansible_distribution_release == "xenial"
diff --git a/prototypes/xci/playbooks/roles/remove-folders/tasks/main.yml b/prototypes/xci/playbooks/roles/remove-folders/tasks/main.yml
deleted file mode 100644 (file)
index 425b8db..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-- name: cleanup leftovers of previous deployment
-  file:
-    path: "{{ item }}"
-    state: absent
-    recurse: no
-  with_items:
-    - "{{ OPNFV_RELENG_PATH }}"
-    - "{{ OPENSTACK_BIFROST_PATH }}"
-    - "{{ OPENSTACK_OSA_PATH }}"
-    - "{{ OPENSTACK_OSA_ETC_PATH }}"
-    - "{{ LOG_PATH }} "
-    - "{{ OPNFV_SSH_HOST_KEYS_PATH }}"
diff --git a/prototypes/xci/playbooks/roles/synchronize-time/tasks/main.yml b/prototypes/xci/playbooks/roles/synchronize-time/tasks/main.yml
deleted file mode 100644 (file)
index 5c39d89..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-# TODO: this role needs to be adjusted for different distros
-- block:
-    - name: restart chrony
-      service:
-        name: chrony
-        state: restarted
-    - name: synchronize time
-      shell: "chronyc -a 'burst 4/4' && chronyc -a makestep"
-  when: ansible_distribution_release == "xenial"
diff --git a/prototypes/xci/scripts/update-osa-version-files.sh b/prototypes/xci/scripts/update-osa-version-files.sh
deleted file mode 100755 (executable)
index d822d25..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/bin/bash
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 SUSE LINUX GmbH and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-
-# This script is used to pin the SHAs for the various roles in the
-# ansible-role-requirements file. It will also update the SHAs for
-# OSA and bifrost.
-
-set -e
-
-# NOTE(hwoarang) This could break if files are re-arranged in the future
-releng_xci_base="$(dirname $(readlink -f $0))/.."
-
-usage() {
-    echo """
-    ${0} <openstack-ansible commit SHA> [<bifrost commit SHA>]
-    """
-    exit 0
-}
-
-cleanup() {
-    [[ -d $tempdir ]] && rm -rf $tempdir
-}
-
-printme() {
-    echo "===> $1"
-}
-
-# Only need a single argument
-[[ $# -lt 1 || $# -gt 2 ]] && echo "Invalid number of arguments!" && usage
-
-tempdir="$(mktemp -d)"
-
-trap cleanup EXIT
-
-pushd $tempdir &> /dev/null
-
-printme "Downloading the sources-branch-updater-lib.sh library"
-
-printme "Cloning the openstack-ansible repository"
-(
-    git clone -q git://git.openstack.org/openstack/openstack-ansible && cd openstack-ansible && git checkout -q $1
-)
-
-popd &> /dev/null
-
-pushd $tempdir/openstack-ansible &> /dev/null
-source scripts/sources-branch-updater-lib.sh
-printme "Synchronize roles and packages"
-update_ansible_role_requirements "master" "true" "true"
-
-# Construct the ansible-role-requirements-file
-echo """---
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-# these versions are extracted based on the osa commit ${1} on $(git --no-pager log -1 --format=%cI $1)
-# https://review.openstack.org/gitweb?p=openstack/openstack-ansible.git;a=commit;h=$1""" > $releng_xci_base/file/ansible-role-requirements.yml
-cat $tempdir/openstack-ansible/ansible-role-requirements.yml >> $releng_xci_base/file/ansible-role-requirements.yml
-
-# Update the pinned OSA version
-sed -i -e "/^export OPENSTACK_OSA_VERSION/s@:-\"[a-z0-9]*@:-\"${1}@" \
-    -e "s/\(^# HEAD of osa.*of \).*/\1$(date +%d\.%m\.%Y)/" $releng_xci_base/config/pinned-versions
-
-# Update the pinned bifrost version
-[[ -n ${2:-} ]] && \
-    sed -i -e "/^export OPENSTACK_BIFROST_VERSION/s@:-\"[a-z0-9]*@:-\"${2}@" \
-    -e "s/\(^# HEAD of bifrost.*of \).*/\1$(date +%d\.%m\.%Y)/" $releng_xci_base/config/pinned-versions
-
-popd &> /dev/null
-
-printme ""
-printme "======================= Report ============================"
-printme ""
-printme "The $releng_xci_base/file/ansible-role-requirements.yml and"
-printme "$releng_xci_base/config/pinned-versions files have been"
-printme "updated. Please make sure you test the end result before"
-printme "committing it!"
-printme ""
-printme "==========================================================="
diff --git a/prototypes/xci/template/compute.interface.j2 b/prototypes/xci/template/compute.interface.j2
deleted file mode 100644 (file)
index 094544c..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# The loopback network interface
-auto lo
-iface lo inet loopback
-
-# Physical interface
-auto {{ interface }}
-iface {{ interface }} inet manual
-
-# Container/Host management VLAN interface
-auto {{ interface }}.10
-iface {{ interface }}.10 inet manual
-    vlan-raw-device {{ interface }}
-
-# OpenStack Networking VXLAN (tunnel/overlay) VLAN interface
-auto {{ interface }}.30
-iface {{ interface }}.30 inet manual
-    vlan-raw-device {{ interface }}
-
-# Storage network VLAN interface
-auto {{ interface }}.20
-iface {{ interface }}.20 inet manual
-    vlan-raw-device {{ interface }}
-
-# Container/Host management bridge
-auto br-mgmt
-iface br-mgmt inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}.10
-    address {{host_info[inventory_hostname].MGMT_IP}}
-    netmask 255.255.252.0
-
-# compute1 VXLAN (tunnel/overlay) bridge config
-auto br-vxlan
-iface br-vxlan inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}.30
-    address {{host_info[inventory_hostname].VXLAN_IP}}
-    netmask 255.255.252.0
-
-# OpenStack Networking VLAN bridge
-auto br-vlan
-iface br-vlan inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}
-    address {{host_info[inventory_hostname].VLAN_IP}}
-    netmask 255.255.255.0
-    gateway 192.168.122.1
-    dns-nameserver 8.8.8.8 8.8.4.4
-    offload-sg off
-    # Create veth pair, don't bomb if already exists
-    pre-up ip link add br-vlan-veth type veth peer name eth12 || true
-    # Set both ends UP
-    pre-up ip link set br-vlan-veth up
-    pre-up ip link set eth12 up
-    # Delete veth pair on DOWN
-    post-down ip link del br-vlan-veth || true
-    bridge_ports br-vlan-veth
-
-# OpenStack Storage bridge
-auto br-storage
-iface br-storage inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}.20
-    address {{host_info[inventory_hostname].STORAGE_IP}}
-    netmask 255.255.252.0
diff --git a/prototypes/xci/template/controller.interface.j2 b/prototypes/xci/template/controller.interface.j2
deleted file mode 100644 (file)
index 638e78e..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-# The loopback network interface
-auto lo
-iface lo inet loopback
-
-# Physical interface
-auto {{ interface }}
-iface {{ interface }} inet manual
-
-# Container/Host management VLAN interface
-auto {{ interface }}.10
-iface {{ interface }}.10 inet manual
-    vlan-raw-device {{ interface }}
-
-# OpenStack Networking VXLAN (tunnel/overlay) VLAN interface
-auto {{ interface }}.30
-iface {{ interface }}.30 inet manual
-    vlan-raw-device {{ interface }}
-
-# Storage network VLAN interface (optional)
-auto {{ interface }}.20
-iface {{ interface }}.20 inet manual
-    vlan-raw-device {{ interface }}
-
-# Container/Host management bridge
-auto br-mgmt
-iface br-mgmt inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}.10
-    address {{host_info[inventory_hostname].MGMT_IP}}
-    netmask 255.255.252.0
-
-# OpenStack Networking VXLAN (tunnel/overlay) bridge
-auto br-vxlan
-iface br-vxlan inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}.30
-    address {{host_info[inventory_hostname].VXLAN_IP}}
-    netmask 255.255.252.0
-
-# OpenStack Networking VLAN bridge
-auto br-vlan
-iface br-vlan inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}
-    address {{host_info[inventory_hostname].VLAN_IP}}
-    netmask 255.255.255.0
-    gateway 192.168.122.1
-    dns-nameserver 8.8.8.8 8.8.4.4
-
-# OpenStack Storage bridge
-auto br-storage
-iface br-storage inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}.20
-    address {{host_info[inventory_hostname].STORAGE_IP}}
-    netmask 255.255.252.0
diff --git a/prototypes/xci/template/opnfv.interface.j2 b/prototypes/xci/template/opnfv.interface.j2
deleted file mode 100644 (file)
index e9f8649..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-# The loopback network interface
-auto lo
-iface lo inet loopback
-
-# Physical interface
-auto {{ interface }}
-iface {{ interface }} inet manual
-
-# Container/Host management VLAN interface
-auto {{ interface }}.10
-iface {{ interface }}.10 inet manual
-    vlan-raw-device {{ interface }}
-
-# OpenStack Networking VXLAN (tunnel/overlay) VLAN interface
-auto {{ interface }}.30
-iface {{ interface }}.30 inet manual
-    vlan-raw-device {{ interface }}
-
-# Storage network VLAN interface (optional)
-auto {{ interface }}.20
-iface {{ interface }}.20 inet manual
-    vlan-raw-device {{ interface }}
-
-# Container/Host management bridge
-auto br-mgmt
-iface br-mgmt inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}.10
-    address {{host_info[inventory_hostname].MGMT_IP}}
-    netmask 255.255.252.0
-
-# OpenStack Networking VXLAN (tunnel/overlay) bridge
-auto br-vxlan
-iface br-vxlan inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}.30
-    address {{ host_info[inventory_hostname].VXLAN_IP }}
-    netmask 255.255.252.0
-
-# OpenStack Networking VLAN bridge
-auto br-vlan
-iface br-vlan inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}
-    address {{host_info[inventory_hostname].VLAN_IP}}
-    netmask 255.255.255.0
-    gateway 192.168.122.1
-    dns-nameserver 8.8.8.8 8.8.4.4
-
-# OpenStack Storage bridge
-auto br-storage
-iface br-storage inet static
-    bridge_stp off
-    bridge_waitport 0
-    bridge_fd 0
-    bridge_ports {{ interface }}.20
-    address {{host_info[inventory_hostname].STORAGE_IP}}
-    netmask 255.255.252.0
diff --git a/prototypes/xci/var/Debian.yml b/prototypes/xci/var/Debian.yml
deleted file mode 100644 (file)
index d13d080..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-# this is the interface the VM nodes are connected to libvirt network "default"
-interface: "ens3"
diff --git a/prototypes/xci/var/RedHat.yml b/prototypes/xci/var/RedHat.yml
deleted file mode 100644 (file)
index 6d03e0f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-# this is placeholder and left blank intentionally to complete later on
diff --git a/prototypes/xci/var/Suse.yml b/prototypes/xci/var/Suse.yml
deleted file mode 100644 (file)
index 6d03e0f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-# this is placeholder and left blank intentionally to complete later on
diff --git a/prototypes/xci/var/opnfv.yml b/prototypes/xci/var/opnfv.yml
deleted file mode 100644 (file)
index aeaface..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
----
-# SPDX-license-identifier: Apache-2.0
-##############################################################################
-# Copyright (c) 2017 Ericsson AB and others.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-OPNFV_RELENG_GIT_URL: "{{ lookup('env','OPNFV_RELENG_GIT_URL') }}"
-OPNFV_RELENG_PATH: "{{ lookup('env','OPNFV_RELENG_PATH') }}"
-OPNFV_RELENG_DEV_PATH: "{{ lookup('env','OPNFV_RELENG_DEV_PATH') }}"
-OPNFV_RELENG_VERSION: "{{ lookup('env','OPNFV_RELENG_VERSION') }}"
-OPENSTACK_BIFROST_GIT_URL: "{{ lookup('env','OPENSTACK_BIFROST_GIT_URL') }}"
-OPENSTACK_BIFROST_PATH: "{{ lookup('env','OPENSTACK_BIFROST_PATH') }}"
-OPENSTACK_BIFROST_DEV_PATH: "{{ lookup('env','OPENSTACK_BIFROST_DEV_PATH') }}"
-OPENSTACK_BIFROST_VERSION: "{{ lookup('env','OPENSTACK_BIFROST_VERSION') }}"
-OPENSTACK_OSA_GIT_URL: "{{ lookup('env','OPENSTACK_OSA_GIT_URL') }}"
-OPENSTACK_OSA_PATH: "{{ lookup('env','OPENSTACK_OSA_PATH') }}"
-OPENSTACK_OSA_DEV_PATH: "{{ lookup('env','OPENSTACK_OSA_DEV_PATH') }}"
-OPENSTACK_OSA_VERSION: "{{ lookup('env','OPENSTACK_OSA_VERSION') }}"
-OPENSTACK_OSA_ETC_PATH: "{{ lookup('env','OPENSTACK_OSA_ETC_PATH') }}"
-XCI_ANSIBLE_PIP_VERSION: "{{ lookup('env','XCI_ANSIBLE_PIP_VERSION') }}"
-XCI_FLAVOR: "{{ lookup('env','XCI_FLAVOR') }}"
-XCI_FLAVOR_ANSIBLE_FILE_PATH: "{{ lookup('env','XCI_FLAVOR_ANSIBLE_FILE_PATH') }}"
-XCI_LOOP: "{{ lookup('env','XCI_LOOP') }}"
-LOG_PATH: "{{ lookup('env','LOG_PATH') }}"
-OPNFV_HOST_IP: "{{ lookup('env','OPNFV_HOST_IP') }}"
-OPNFV_SSH_HOST_KEYS_PATH: "{{ lookup('env', 'OPNFV_SSH_HOST_KEYS_PATH') }}"
-XCI_EXTRA_VARS_PATH: "{{ lookup('env', 'XCI_EXTRA_VARS_PATH') }}"
diff --git a/prototypes/xci/xci-deploy.sh b/prototypes/xci/xci-deploy.sh
deleted file mode 100755 (executable)
index 3a65983..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-#!/bin/bash
-set -o errexit
-set -o nounset
-set -o pipefail
-
-#-------------------------------------------------------------------------------
-# This script should not be run as root
-#-------------------------------------------------------------------------------
-if [[ $(whoami) == "root" ]]; then
-    echo "WARNING: This script should not be run as root!"
-    echo "Elevated privileges are aquired automatically when necessary"
-    echo "Waiting 10s to give you a chance to stop the script (Ctrl-C)"
-    for x in $(seq 10 -1 1); do echo -n "$x..."; sleep 1; done
-fi
-
-#-------------------------------------------------------------------------------
-# Set environment variables
-#-------------------------------------------------------------------------------
-# The order of sourcing the variable files is significant so please do not
-# change it or things might stop working.
-# - user-vars: variables that can be configured or overriden by user.
-# - pinned-versions: versions to checkout. These can be overriden if you want to
-#   use different/more recent versions of the tools but you might end up using
-#   something that is not verified by OPNFV XCI.
-# - flavor-vars: settings for VM nodes for the chosen flavor.
-# - env-vars: variables for the xci itself and you should not need to change or
-#   override any of them.
-#-------------------------------------------------------------------------------
-# find where are we
-XCI_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-# source user vars
-source $XCI_PATH/config/user-vars
-# source pinned versions
-source $XCI_PATH/config/pinned-versions
-# source flavor configuration
-source "$XCI_PATH/config/${XCI_FLAVOR}-vars"
-# source xci configuration
-source $XCI_PATH/config/env-vars
-
-#-------------------------------------------------------------------------------
-# Log info to console
-#-------------------------------------------------------------------------------
-echo "Info: Starting XCI Deployment"
-echo "Info: Deployment parameters"
-echo "-------------------------------------------------------------------------"
-echo "xci flavor: $XCI_FLAVOR"
-echo "opnfv/releng version: $OPNFV_RELENG_VERSION"
-echo "openstack/bifrost version: $OPENSTACK_BIFROST_VERSION"
-echo "openstack/openstack-ansible version: $OPENSTACK_OSA_VERSION"
-echo "-------------------------------------------------------------------------"
-
-#-------------------------------------------------------------------------------
-# Install ansible on localhost
-#-------------------------------------------------------------------------------
-source file/install-ansible.sh
-
-# TODO: The xci playbooks can be put into a playbook which will be done later.
-
-#-------------------------------------------------------------------------------
-# Start provisioning VM nodes
-#-------------------------------------------------------------------------------
-# This playbook
-# - removes directories that were created by the previous xci run
-# - clones opnfv/releng and openstack/bifrost repositories
-# - combines opnfv/releng and openstack/bifrost scripts/playbooks
-# - destorys VMs, removes ironic db, leases, logs
-# - creates and provisions VMs for the chosen flavor
-#-------------------------------------------------------------------------------
-echo "Info: Starting provisining VM nodes using openstack/bifrost"
-echo "-------------------------------------------------------------------------"
-cd $XCI_PATH/playbooks
-ansible-playbook $ANSIBLE_VERBOSITY -i inventory provision-vm-nodes.yml
-echo "-----------------------------------------------------------------------"
-echo "Info: VM nodes are provisioned!"
-source $OPENSTACK_BIFROST_PATH/env-vars
-ironic node-list
-echo
-#-------------------------------------------------------------------------------
-# Configure localhost
-#-------------------------------------------------------------------------------
-# This playbook
-# - removes directories that were created by the previous xci run
-# - clones opnfv/releng repository
-# - creates log directory
-# - copies flavor files such as playbook, inventory, and var file
-#-------------------------------------------------------------------------------
-echo "Info: Configuring localhost for openstack-ansible"
-echo "-----------------------------------------------------------------------"
-cd $XCI_PATH/playbooks
-ansible-playbook $ANSIBLE_VERBOSITY -i inventory configure-localhost.yml
-echo "-----------------------------------------------------------------------"
-echo "Info: Configured localhost host for openstack-ansible"
-
-#-------------------------------------------------------------------------------
-# Configure openstack-ansible deployment host, opnfv
-#-------------------------------------------------------------------------------
-# This playbook
-# - removes directories that were created by the previous xci run
-# - clones opnfv/releng and openstack/openstack-ansible repositories
-# - configures network
-# - generates/prepares ssh keys
-# - bootstraps ansible
-# - copies flavor files to be used by openstack-ansible
-#-------------------------------------------------------------------------------
-echo "Info: Configuring opnfv deployment host for openstack-ansible"
-echo "-----------------------------------------------------------------------"
-cd $OPNFV_RELENG_PATH/prototypes/xci/playbooks
-ansible-playbook $ANSIBLE_VERBOSITY -i inventory configure-opnfvhost.yml
-echo "-----------------------------------------------------------------------"
-echo "Info: Configured opnfv deployment host for openstack-ansible"
-
-#-------------------------------------------------------------------------------
-# Skip the rest if the flavor is aio since the target host for aio is opnfv
-#-------------------------------------------------------------------------------
-if [[ $XCI_FLAVOR == "aio" ]]; then
-    echo "xci: aio has been installed"
-    exit 0
-fi
-
-#-------------------------------------------------------------------------------
-# Configure target hosts for openstack-ansible
-#-------------------------------------------------------------------------------
-# This playbook
-# - adds public keys to target hosts
-# - configures network
-# - configures nfs
-#-------------------------------------------------------------------------------
-echo "Info: Configuring target hosts for openstack-ansible"
-echo "-----------------------------------------------------------------------"
-cd $OPNFV_RELENG_PATH/prototypes/xci/playbooks
-ansible-playbook $ANSIBLE_VERBOSITY -i inventory configure-targethosts.yml
-echo "-----------------------------------------------------------------------"
-echo "Info: Configured target hosts"
-
-#-------------------------------------------------------------------------------
-# Set up target hosts for openstack-ansible
-#-------------------------------------------------------------------------------
-# This is openstack-ansible playbook. Check upstream documentation for details.
-#-------------------------------------------------------------------------------
-echo "Info: Setting up target hosts for openstack-ansible"
-echo "-----------------------------------------------------------------------"
-ssh root@$OPNFV_HOST_IP "openstack-ansible \
-     $OPENSTACK_OSA_PATH/playbooks/setup-hosts.yml" | \
-     tee $LOG_PATH/setup-hosts.log
-echo "-----------------------------------------------------------------------"
-# check the log to see if we have any error
-if grep -q 'failed=1\|unreachable=1' $LOG_PATH/setup-hosts.log; then
-    echo "Error: OpenStack node setup failed!"
-    exit 1
-fi
-echo "Info: Set up target hosts for openstack-ansible successfuly"
-
-#-------------------------------------------------------------------------------
-# Set up infrastructure
-#-------------------------------------------------------------------------------
-# This is openstack-ansible playbook. Check upstream documentation for details.
-#-------------------------------------------------------------------------------
-echo "Info: Setting up infrastructure"
-echo "-----------------------------------------------------------------------"
-echo "xci: running ansible playbook setup-infrastructure.yml"
-ssh root@$OPNFV_HOST_IP "openstack-ansible \
-     $OPENSTACK_OSA_PATH/playbooks//setup-infrastructure.yml" | \
-     tee $LOG_PATH/setup-infrastructure.log
-echo "-----------------------------------------------------------------------"
-# check the log to see if we have any error
-if grep -q 'failed=1\|unreachable=1' $LOG_PATH/setup-infrastructure.log; then
-    echo "Error: OpenStack node setup failed!"
-    exit 1
-fi
-
-#-------------------------------------------------------------------------------
-# Verify database cluster
-#-------------------------------------------------------------------------------
-echo "Info: Verifying database cluster"
-echo "-----------------------------------------------------------------------"
-ssh root@$OPNFV_HOST_IP "ansible -i $OPENSTACK_OSA_PATH/playbooks/inventory/ \
-           galera_container -m shell \
-           -a "mysql -h localhost -e 'show status like \"%wsrep_cluster_%\";'"" \
-           | tee $LOG_PATH/galera.log
-echo "-----------------------------------------------------------------------"
-# check the log to see if we have any error
-if grep -q 'FAILED' $LOG_PATH/galera.log; then
-    echo "Error: Database cluster verification failed!"
-    exit 1
-fi
-echo "Info: Database cluster verification successful!"
-
-#-------------------------------------------------------------------------------
-# Install OpenStack
-#-------------------------------------------------------------------------------
-# This is openstack-ansible playbook. Check upstream documentation for details.
-#-------------------------------------------------------------------------------
-echo "Info: Installing OpenStack on target hosts"
-echo "-----------------------------------------------------------------------"
-ssh root@$OPNFV_HOST_IP "openstack-ansible \
-     $OPENSTACK_OSA_PATH/playbooks/setup-openstack.yml" | \
-     tee $LOG_PATH/opnfv-setup-openstack.log
-echo "-----------------------------------------------------------------------"
-# check the log to see if we have any error
-if grep -q 'failed=1\|unreachable=1' $LOG_PATH/opnfv-setup-openstack.log; then
-   echo "Error: OpenStack installation failed!"
-   exit 1
-fi
-echo "Info: OpenStack installation is successfully completed!"
diff --git a/setup.py b/setup.py
deleted file mode 100644 (file)
index 3c93408..0000000
--- a/setup.py
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env python
-
-from setuptools import setup
-
-setup(
-    name="releng",
-    version="master",
-    url="https://www.opnfv.org",
-)
diff --git a/tox.ini b/tox.ini
index e9f5fbb..d3489e5 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -8,27 +8,13 @@ envlist = py27
 skipsdist = True
 
 [testenv]
-usedevelop = True
+usedevelop = False
 setenv=
   HOME = {envtmpdir}
   PYTHONPATH = {toxinidir}
 
 [testenv:jjb]
 deps =
-       -rjjb/test-requirements.txt
+  jenkins-job-builder==1.6.1
 commands=
-       jenkins-jobs test -o job_output -r jjb/
-
-[testenv:modules]
-deps=
-       -rmodules/requirements.txt
-       -rmodules/test-requirements.txt
-commands =
-       nosetests -w modules \
-       --with-xunit \
-       --xunit-file=modules/nosetests.xml \
-       --cover-package=opnfv \
-       --with-coverage \
-       --cover-xml \
-       --cover-html \
-       tests/unit
+  jenkins-jobs test -o job_output -r jjb/
index 197e493..def5ecc 100644 (file)
@@ -12,6 +12,8 @@ parser.add_argument("-u", "--user", help="Give username of this pod")
 parser.add_argument("-k", "--key", help="Give key file of the user")
 parser.add_argument("-p", "--password", help="Give password of the user")
 parser.add_argument("-f", "--filepath", help="Give dest path of output file")
+parser.add_argument("-s", "--sshkey", default="/root/.ssh/id_rsa",
+                    help="Give the path for ssh key")
 args = parser.parse_args()
 
 
@@ -49,7 +51,7 @@ def get_with_passwd():
                                        args.user, installer_pwd=args.password)
 
 
-def create_file(handler):
+def create_file(handler, INSTALLER_TYPE):
     """
     Create the yaml file of nodes info.
     As Yardstick required, node name must be node1, node2, ... and node1 must
@@ -62,34 +64,37 @@ def create_file(handler):
     nodes = handler.nodes
     node_list = []
     index = 1
+    user = 'root'
+    if INSTALLER_TYPE == 'apex':
+        user = 'heat-admin'
     for node in nodes:
         try:
             if node.roles[0].lower() == "controller":
                 node_info = {'name': "node%s" % index, 'role': node.roles[0],
-                             'ip': node.ip, 'user': 'root'}
+                             'ip': node.ip, 'user': user}
                 node_list.append(node_info)
                 index += 1
         except Exception:
             node_info = {'name': node.name, 'role': 'unknown', 'ip': node.ip,
-                         'user': 'root'}
+                         'user': user}
             node_list.append(node_info)
     for node in nodes:
         try:
             if node.roles[0].lower() == "compute":
                 node_info = {'name': "node%s" % index, 'role': node.roles[0],
-                             'ip': node.ip, 'user': 'root'}
+                             'ip': node.ip, 'user': user}
                 node_list.append(node_info)
                 index += 1
         except Exception:
             node_info = {'name': node.name, 'role': 'unknown', 'ip': node.ip,
-                         'user': 'root'}
+                         'user': user}
             node_list.append(node_info)
     if args.INSTALLER_TYPE == 'compass':
         for item in node_list:
             item['password'] = 'root'
     else:
         for item in node_list:
-            item['key_filename'] = '/root/.ssh/id_rsa'
+            item['key_filename'] = args.sshkey
     data = {'nodes': node_list}
     with open(args.filepath, "w") as fw:
         yaml.dump(data, fw)
@@ -105,7 +110,7 @@ def main():
     if not handler:
         print("Error: failed to get the node's handler.")
         return 1
-    create_file(handler)
+    create_file(handler, args.INSTALLER_TYPE)
 
 
 if __name__ == '__main__':
index 993c0b9..0873a68 100755 (executable)
@@ -12,7 +12,7 @@ set -o nounset
 set -o pipefail
 
 usage() {
-    echo "usage: $0 [-v] -d <destination> -i <installer_type> -a <installer_ip> [-s <ssh_key>]" >&2
+    echo "usage: $0 [-v] -d <destination> -i <installer_type> -a <installer_ip> [-o <os_cacert>] [-s <ssh_key>]" >&2
     echo "[-v] Virtualized deployment" >&2
     echo "[-s <ssh_key>] Path to ssh key. For MCP deployments only" >&2
 }
@@ -54,12 +54,13 @@ swap_to_public() {
 : ${DEPLOY_TYPE:=''}
 
 #Get options
-while getopts ":d:i:a:h:s:v" optchar; do
+while getopts ":d:i:a:h:s:o:v" optchar; do
     case "${optchar}" in
         d) dest_path=${OPTARG} ;;
         i) installer_type=${OPTARG} ;;
         a) installer_ip=${OPTARG} ;;
         s) ssh_key=${OPTARG} ;;
+        o) os_cacert=${OPTARG} ;;
         v) DEPLOY_TYPE="virt" ;;
         *) echo "Non-option argument: '-${OPTARG}'" >&2
            usage
@@ -70,11 +71,9 @@ done
 
 # set vars from env if not provided by user as options
 dest_path=${dest_path:-$HOME/opnfv-openrc.sh}
+os_cacert=${os_cacert:-$HOME/os_cacert}
 installer_type=${installer_type:-$INSTALLER_TYPE}
 installer_ip=${installer_ip:-$INSTALLER_IP}
-if [ "${installer_type}" == "fuel" ] && [ "${BRANCH}" == "master" ]; then
-    installer_ip=${SALT_MASTER_IP}
-fi
 
 if [ -z $dest_path ] || [ -z $installer_type ] || [ -z $installer_ip ]; then
     usage
@@ -93,25 +92,33 @@ fi
 ssh_options="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
 
 # Start fetching the files
+info "Fetching rc file..."
 if [ "$installer_type" == "fuel" ]; then
-    verify_connectivity $installer_ip
-    if [ "${BRANCH}" == "master" ]; then
-        ssh_key=${ssh_key:-$SSH_KEY}
-        if [ -z $ssh_key ] || [ ! -f $ssh_key ]; then
+    verify_connectivity "${installer_ip}"
+    # stable/danube uses old Fuel, requires user/pass; new Fuel uses keypair
+    if [[ ! "${BRANCH}" =~ "danube" ]]; then
+        ssh_user="ubuntu"
+        ssh_key="${ssh_key:-$SSH_KEY}"
+        if [ -z "$ssh_key" ] || [ ! -f "$ssh_key" ]; then
             error "Please provide path to existing ssh key for mcp deployment."
             exit 2
         fi
         ssh_options+=" -i ${ssh_key}"
 
         # retrieving controller vip
-        controller_ip=$(ssh 2>/dev/null ${ssh_options} ubuntu@${installer_ip} \
-            "sudo salt --out txt 'ctl01*' pillar.get _param:openstack_control_address | awk '{print \$2}'" | \
-            sed 's/ //g') &> /dev/null
+        controller_ip=$(ssh 2>/dev/null ${ssh_options} "${ssh_user}@${installer_ip}" \
+            "sudo salt --out yaml 'ctl*' pillar.get _param:openstack_control_address | \
+                awk '{print \$2; exit}'") &> /dev/null
+
+        info "... from controller ${controller_ip} ..."
+        ssh ${ssh_options} "${ssh_user}@${controller_ip}" \
+            "sudo cat /root/keystonercv3" > "${dest_path}"
 
-        info "Fetching rc file from controller $controller_ip..."
-        ssh ${ssh_options} ubuntu@${controller_ip} "sudo cat /root/keystonercv3" > $dest_path
+        if [[ "${BUILD_TAG}" =~ "baremetal" ]]; then
+            ssh ${ssh_options} "${ssh_user}@${installer_ip}" \
+                "cat /etc/ssl/certs/os_cacert" > "${os_cacert}"
+        fi
     else
-        #ip_fuel="10.20.0.2"
         env=$(sshpass -p r00tme ssh 2>/dev/null ${ssh_options} root@${installer_ip} \
             'fuel env'|grep operational|head -1|awk '{print $1}') &> /dev/null
         if [ -z $env ]; then
@@ -128,7 +135,7 @@ if [ "$installer_type" == "fuel" ]; then
             error "The controller $controller_ip is not up. Please check that the POD is correctly deployed."
         fi
 
-        info "Fetching rc file from controller $controller_ip..."
+        info "... from controller $controller_ip..."
         sshpass -p r00tme ssh 2>/dev/null ${ssh_options} root@${installer_ip} \
             "scp ${ssh_options} ${controller_ip}:/root/openrc ." &> /dev/null
         sshpass -p r00tme scp 2>/dev/null ${ssh_options} root@${installer_ip}:~/openrc $dest_path &> /dev/null
@@ -142,52 +149,64 @@ if [ "$installer_type" == "fuel" ]; then
     echo $auth_url >> $dest_path
 
 elif [ "$installer_type" == "apex" ]; then
+    if ! ipcalc -c $installer_ip; then
+      installer_ip=$(sudo virsh domifaddr undercloud | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
+      if [ -z "$installer_ip" ] || ! $(ipcalc -c $installer_ip); then
+        echo "Unable to find valid IP for Apex undercloud: ${installer_ip}"
+        exit 1
+      fi
+    fi
     verify_connectivity $installer_ip
 
     # The credentials file is located in the Instack VM (192.0.2.1)
     # NOTE: This might change for bare metal deployments
-    info "Fetching rc file from Instack VM $installer_ip..."
+    info "... from Instack VM $installer_ip..."
     if [ -f /root/.ssh/id_rsa ]; then
         chmod 600 /root/.ssh/id_rsa
     fi
     sudo scp $ssh_options root@$installer_ip:/home/stack/overcloudrc.v3 $dest_path
 
 elif [ "$installer_type" == "compass" ]; then
-    verify_connectivity $installer_ip
-    controller_ip=$(sshpass -p'root' ssh 2>/dev/null $ssh_options root@${installer_ip} \
-        'mysql -ucompass -pcompass -Dcompass -e"select *  from cluster;"' \
-        | awk -F"," '{for(i=1;i<NF;i++)if($i~/\"127.0.0.1\"/) {print $(i+2);break;}}'  \
-        | grep -oP "\d+.\d+.\d+.\d+")
-
-    if [ -z $controller_ip ]; then
-        error "The controller $controller_ip is not up. Please check that the POD is correctly deployed."
-    fi
-
-    info "Fetching rc file from controller $controller_ip..."
-    sshpass -p root ssh 2>/dev/null $ssh_options root@${installer_ip} \
-        "scp $ssh_options ${controller_ip}:/opt/admin-openrc.sh ." &> /dev/null
-    sshpass -p root scp 2>/dev/null $ssh_options root@${installer_ip}:~/admin-openrc.sh $dest_path &> /dev/null
+    if [ "${BRANCH}" == "master" ]; then
+        sudo docker cp compass-tasks:/opt/openrc $dest_path &> /dev/null
+        sudo chown $(whoami):$(whoami) $dest_path
+        sudo docker cp compass-tasks:/opt/os_cacert $os_cacert
+    else
+        verify_connectivity $installer_ip
+        controller_ip=$(sshpass -p'root' ssh 2>/dev/null $ssh_options root@${installer_ip} \
+            'mysql -ucompass -pcompass -Dcompass -e"select *  from cluster;"' \
+            | awk -F"," '{for(i=1;i<NF;i++)if($i~/\"127.0.0.1\"/) {print $(i+2);break;}}'  \
+            | grep -oP "\d+.\d+.\d+.\d+")
 
-    info "This file contains the mgmt keystone API, we need the public one for our rc file"
+        if [ -z $controller_ip ]; then
+            error "The controller $controller_ip is not up. Please check that the POD is correctly deployed."
+        fi
 
-    if grep "OS_AUTH_URL.*v2" $dest_path > /dev/null 2>&1 ; then
-        public_ip=$(sshpass -p root ssh $ssh_options root@${installer_ip} \
-            "ssh ${controller_ip} 'source /opt/admin-openrc.sh; openstack endpoint show identity '" \
-            | grep publicurl | awk '{print $4}')
-    else
-        public_ip=$(sshpass -p root ssh $ssh_options root@${installer_ip} \
-            "ssh ${controller_ip} 'source /opt/admin-openrc.sh; \
-                 openstack endpoint list --interface public --service identity '" \
-            | grep identity | awk '{print $14}')
+        info "... from controller $controller_ip..."
+        sshpass -p root ssh 2>/dev/null $ssh_options root@${installer_ip} \
+            "scp $ssh_options ${controller_ip}:/opt/admin-openrc.sh ." &> /dev/null
+        sshpass -p root scp 2>/dev/null $ssh_options root@${installer_ip}:~/admin-openrc.sh $dest_path &> /dev/null
+
+        info "This file contains the mgmt keystone API, we need the public one for our rc file"
+
+        if grep "OS_AUTH_URL.*v2" $dest_path > /dev/null 2>&1 ; then
+            public_ip=$(sshpass -p root ssh $ssh_options root@${installer_ip} \
+                "ssh ${controller_ip} 'source /opt/admin-openrc.sh; openstack endpoint show identity '" \
+                | grep publicurl | awk '{print $4}')
+        else
+            public_ip=$(sshpass -p root ssh $ssh_options root@${installer_ip} \
+                "ssh ${controller_ip} 'source /opt/admin-openrc.sh; \
+                     openstack endpoint list --interface public --service identity '" \
+                | grep identity | awk '{print $14}')
+        fi
+        info "public_ip: $public_ip"
+        swap_to_public $public_ip
     fi
-    info "public_ip: $public_ip"
-    swap_to_public $public_ip
-
 
 elif [ "$installer_type" == "joid" ]; then
     # do nothing...for the moment
     # we can either do a scp from the jumphost or use the -v option to transmit the param to the docker file
-    echo "Do nothing, creds will be provided through volume option at docker creation for joid"
+    info "Do nothing, creds will be provided through volume option at docker creation for joid"
 
 elif [ "$installer_type" == "foreman" ]; then
     #ip_foreman="172.30.10.73"
@@ -224,6 +243,10 @@ elif [ "$installer_type" == "daisy" ]; then
 
     sshpass -p r00tme scp 2>/dev/null $ssh_options root@${installer_ip}:/etc/kolla/admin-openrc.sh $dest_path &> /dev/null
 
+elif ["$installer_type" == "osa"]; then
+    # Get RC file from control server
+    filename=$(ssh -o StrictHostKeyChecking=no root@${controller_ip} find /var/lib/lxc/controller00_nova_api_placement_container-* -name openrc)
+    scp root@${controller_ip}:${filename} ${destpath}
 else
     error "Installer $installer is not supported by this script"
 fi
index 5021b78..518d20a 100644 (file)
@@ -27,10 +27,12 @@ node_list=(\
 'ericsson-pod1' 'ericsson-pod2' \
 'ericsson-virtual1' 'ericsson-virtual2'  'ericsson-virtual3' \
 'ericsson-virtual4' 'ericsson-virtual5' 'ericsson-virtual12' \
-'arm-pod1' 'arm-pod3' \
+'arm-pod1' 'arm-pod5' \
 'huawei-pod1' 'huawei-pod2' 'huawei-pod3' 'huawei-pod4' 'huawei-pod5' \
 'huawei-pod6' 'huawei-pod7' 'huawei-pod12' \
-'huawei-virtual1' 'huawei-virtual2' 'huawei-virtual3' 'huawei-virtual4'\
+'huawei-virtual1' 'huawei-virtual2' 'huawei-virtual3' 'huawei-virtual4' \
+'huawei-virtual5' 'huawei-virtual8' 'huawei-virtual9' \
+'zte-pod2' \
 'zte-virtual1')
 
 
diff --git a/utils/slave-monitor-0.1.sh b/utils/slave-monitor-0.1.sh
new file mode 100644 (file)
index 0000000..161aaef
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/bash
+# SPDX-license-identifier: Apache-2.0
+##############################################################################
+# Copyright (c) 2016 Linux Foundation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+#This will put a bunch of files in the pwd. you have been warned.
+#Counts how long slaves have been online or offline
+
+
+#Yes I know about jq
+curlcommand() {
+curl -s "https://build.opnfv.org/ci/computer/api/json?tree=computer\[displayName,offline\]" \
+    | awk -v k=":" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' \
+    | grep -v "_class" \
+    | awk 'NR%2{printf "%s ",$0;next;}1'  \
+    | awk -F":" '{print $2,$3}' \
+    | awk '{print $1,$3}' \
+    | sed s,\},,g \
+    | sed s,],,g \
+    | sed s,\",,g
+}
+
+if [ -f podoutput-current ]; then
+  cp podoutput-current podoutput-lastiteration
+fi
+
+curlcommand > podoutput-current
+
+declare -A slavescurrent slaveslastiteration
+
+while read -r name status ; do
+            slavescurrent["$name"]="$status"
+done < <(cat podoutput-current)
+
+while read -r name status ; do
+            slaveslastiteration["$name"]=$status
+done < <(cat podoutput-lastiteration)
+
+main () {
+for slavename in "${!slavescurrent[@]}"; do
+    #Slave is online. Mark it down.
+    if [ "${slavescurrent[$slavename]}" == "false" ]; then
+
+        if  [ -f "$slavename"-offline ]; then
+            echo "removing offline status from $slavename slave was offline for $(cat "$slavename"-offline ) iterations"
+            rm "$slavename"-offline
+        fi
+
+        if  ! [ -f "$slavename"-online ]; then
+            echo "1" > "$slavename"-online
+        elif [ -f "$slavename"-online ]; then
+            #read and increment slavename
+            read -r -d $'\x04' var < "$slavename"-online
+            ((var++))
+            echo -n "ONLINE $slavename "
+            echo "for $var iterations"
+            echo "$var" > "$slavename"-online
+        fi
+    fi
+
+    #went offline since last iteration.
+    if [ "${slavescurrent[$slavename]}" == "false" ] && [ "${slaveslastiteration[$slavename]}" == "true" ];  then
+        echo "JUST WENT OFFLINE $slavename "
+        if  [ -f "$slavename"-online ]; then
+            echo "removing online status from $slavename. slave was online for $(cat "$slavename"-online ) iterations"
+            rm "$slavename"-online
+        fi
+
+    fi
+
+    #slave is offline
+    if [ "${slavescurrent[$slavename]}" == "true" ]; then
+        if  ! [ -f "$slavename"-offline ]; then
+            echo "1" > "$slavename"-offline
+        fi
+
+        if [ -f "$slavename"-offline ]; then
+            #read and increment slavename
+            read -r -d $'\x04' var < "$slavename"-offline
+            ((var++))
+            echo "$var" > "$slavename"-offline
+                if  [ "$var" -gt "30" ]; then
+                    echo "OFFLINE FOR $var ITERATIONS REMOVE $slavename "
+                else
+                    echo "OFFLINE $slavename FOR $var ITERATIONS "
+                fi
+        fi
+    fi
+
+done
+}
+
+main
@@ -7,6 +7,7 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 import requests
+import time
 
 from tornado.escape import json_encode
 from tornado.escape import json_decode
@@ -24,7 +25,7 @@ class FiltersHandler(BaseHandler):
                 'status': ['success', 'warning', 'danger'],
                 'projects': ['functest', 'yardstick'],
                 'installers': ['apex', 'compass', 'fuel', 'joid'],
-                'version': ['colorado', 'master'],
+                'version': ['master', 'colorado', 'danube'],
                 'loops': ['daily', 'weekly', 'monthly'],
                 'time': ['10 days', '30 days']
             }
@@ -53,27 +54,27 @@ class ScenariosHandler(BaseHandler):
     def _get_scenario_result(self, scenario, data, args):
         result = {
             'status': data.get('status'),
-            'installers': self._get_installers_result(data['installers'], args)
+            'installers': self._get_installers_result(data, args)
         }
         return result
 
     def _get_installers_result(self, data, args):
         func = self._get_installer_result
-        return {k: func(k, data.get(k, {}), args) for k in args['installers']}
+        return {k: func(data.get(k, {}), args) for k in args['installers']}
 
-    def _get_installer_result(self, installer, data, args):
-        projects = data.get(args['version'], [])
-        return [self._get_project_data(projects, p) for p in args['projects']]
+    def _get_installer_result(self, data, args):
+        return self._get_version_data(data.get(args['version'], {}), args)
 
-    def _get_project_data(self, projects, project):
+    def _get_version_data(self, data, args):
+        return {k: self._get_project_data(data.get(k, {}))
+                for k in args['projects']}
+
+    def _get_project_data(self, data):
         atom = {
-            'project': project,
-            'score': None,
-            'status': None
+            'score': data.get('score', ''),
+            'status': data.get('status', '')
         }
-        for p in projects:
-            if p['project'] == project:
-                return p
+
         return atom
 
     def _get_scenarios(self):
@@ -88,41 +89,42 @@ class ScenariosHandler(BaseHandler):
                                                                     [])
                                                               ) for a in data}
         scenario = {
-            'status': self._get_status(),
-            'installers': installers
+            'status': self._get_status()
         }
+        scenario.update(installers)
+
         return scenario
 
     def _get_status(self):
         return 'success'
 
     def _get_installer(self, data):
-        return {a.get('version'): self._get_version(a) for a in data}
+        return {a.get('version'): self._get_version(a.get('projects'))
+                for a in data}
 
     def _get_version(self, data):
+        return {a.get('project'): self._get_project(a) for a in data}
+
+    def _get_project(self, data):
+        scores = data.get('scores', [])
+        trusts = data.get('trust_indicators', [])
+
         try:
-            scores = data.get('score', {}).get('projects')[0]
-            trusts = data.get('trust_indicator', {}).get('projects')[0]
-        except (TypeError, IndexError):
-            return []
-        else:
-            scores = {key: [dict(date=a.get('date')[:10],
-                                 score=a.get('score')
-                                 ) for a in scores[key]] for key in scores}
-            trusts = {key: [dict(date=a.get('date')[:10],
-                                 status=a.get('status')
-                                 ) for a in trusts[key]] for key in trusts}
-            atom = self._get_atom(scores, trusts)
-            return [dict(project=k,
-                         score=sorted(atom[k], reverse=True)[0].get('score'),
-                         status=sorted(atom[k], reverse=True)[0].get('status')
-                         ) for k in atom if atom[k]]
-
-    def _get_atom(self, scores, trusts):
-        s = {k: {a['date']: a['score'] for a in scores[k]} for k in scores}
-        t = {k: {a['date']: a['status'] for a in trusts[k]} for k in trusts}
-        return {k: [dict(score=s[k][a], status=t[k][a], data=a
-                         ) for a in s[k] if a in t[k]] for k in s}
+            date = sorted(scores, reverse=True)[0].get('date')
+        except IndexError:
+            data = time.time()
+
+        try:
+            score = sorted(scores, reverse=True)[0].get('score')
+        except IndexError:
+            score = None
+
+        try:
+            status = sorted(trusts, reverse=True)[0].get('status')
+        except IndexError:
+            status = None
+
+        return {'date': date, 'score': score, 'status': status}
 
     def _change_to_utf8(self, obj):
         if isinstance(obj, dict):
diff --git a/utils/test/reporting/api/requirements.txt b/utils/test/reporting/api/requirements.txt
deleted file mode 100644 (file)
index 12ad688..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-tornado==4.4.2
-requests==2.1.0
-
diff --git a/utils/test/reporting/api/setup.cfg b/utils/test/reporting/api/setup.cfg
deleted file mode 100644 (file)
index 53d1092..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-[metadata]
-name = reporting
-
-author = JackChan
-author-email = chenjiankun1@huawei.com
-
-classifier =
-    Environment :: opnfv
-    Intended Audience :: Information Technology
-    Intended Audience :: System Administrators
-    License :: OSI Approved :: Apache Software License
-    Operating System :: POSIX :: Linux
-    Programming Language :: Python
-    Programming Language :: Python :: 2
-    Programming Language :: Python :: 2.7
-
-[global]
-setup-hooks =
-    pbr.hooks.setup_hook
-
-[files]
-packages =
-    api
-
-[entry_points]
-console_scripts =
-    api = api.server:main
-
-[egg_info]
-tag_build =
-tag_date = 0
-tag_svn_revision = 0
diff --git a/utils/test/reporting/api/setup.py b/utils/test/reporting/api/setup.py
deleted file mode 100644 (file)
index d974816..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-import setuptools
-
-
-__author__ = 'JackChan'
-
-
-setuptools.setup(
-    setup_requires=['pbr>=1.8'],
-    pbr=True)
index ad278ce..f235790 100644 (file)
 FROM nginx:stable
 
 MAINTAINER Morgan Richomme <morgan.richomme@orange.com>
-LABEL version="danube.1.0" description="OPNFV Test Reporting Docker container"
+LABEL version="1.0" description="OPNFV Test Reporting Docker container"
 
 ARG BRANCH=master
 
 ENV HOME /home/opnfv
-ENV working_dir /home/opnfv/utils/test/reporting
-ENV TERM xterm
-ENV COLORTERM gnome-terminal
-ENV CONFIG_REPORTING_YAML /home/opnfv/utils/test/reporting/reporting.yaml
+ENV working_dir ${HOME}/releng/utils/test/reporting
+ENV CONFIG_REPORTING_YAML ${working_dir}/reporting.yaml
 
+WORKDIR ${HOME}
 # Packaged dependencies
 RUN apt-get update && apt-get install -y \
+build-essential \
 ssh \
+curl \
+gnupg \
 python-pip \
+python-dev \
+python-setuptools \
 git-core \
-wkhtmltopdf \
-nodejs \
-npm \
 supervisor \
 --no-install-recommends
 
-RUN pip install --upgrade pip
+RUN pip install --upgrade pip && easy_install -U setuptools==30.0.0
 
-RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng /home/opnfv
-RUN pip install -r ${working_dir}/docker/requirements.pip
+RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng /home/opnfv/releng
+RUN pip install -r ${working_dir}/requirements.txt
 
-WORKDIR ${working_dir}/api
-RUN pip install -r requirements.txt
-RUN python setup.py install
+RUN sh -c 'curl -sL https://deb.nodesource.com/setup_8.x | bash -' \
+    && apt-get install -y nodejs \
+    && npm install -g bower \
+    && npm install -g grunt \
+    && npm install -g grunt-cli
 
 WORKDIR ${working_dir}
+RUN python setup.py install
 RUN docker/reporting.sh
+RUN docker/web_server.sh
 
 expose 8000
 
index 9e26972..95baf0e 100644 (file)
@@ -11,14 +11,14 @@ server {
     server_name localhost;
 
     location / {
-        proxy_pass http://backends;
+        alias /home/opnfv/releng/utils/test/reporting/pages/dist/;
     }
 
-    location /reporting/ {
-        alias /home/opnfv/utils/test/reporting/pages/dist/;
+    location /api/ {
+        http_pass http://backends/;
     }
 
     location /display/ {
-        alias /home/opnfv/utils/test/reporting/display/;
+        alias /home/opnfv/releng/utils/test/reporting/display/;
     }
 }
index 49f4517..6cc7a7c 100755 (executable)
@@ -1,10 +1,10 @@
 #!/bin/bash
 
-export PYTHONPATH="${PYTHONPATH}:."
-export CONFIG_REPORTING_YAML=./reporting.yaml
+export PYTHONPATH="${PYTHONPATH}:./reporting"
+export CONFIG_REPORTING_YAML=./reporting/reporting.yaml
 
 declare -a versions=(danube master)
-declare -a projects=(functest storperf yardstick)
+declare -a projects=(functest storperf yardstick qtip vsperf bottlenecks)
 
 project=$1
 reporting_type=$2
@@ -29,8 +29,10 @@ cp -Rf js display
 #  projet   |        option
 #   $1      |          $2
 # functest  | status, vims, tempest
-# yardstick |
-# storperf  |
+# yardstick | status
+# storperf  | status
+# qtip      | status
+# vsperf    | status
 
 function report_project()
 {
@@ -40,7 +42,7 @@ function report_project()
   echo "********************************"
   echo " $project reporting "
   echo "********************************"
-  python ./$dir/reporting-$type.py
+  python ./reporting/$dir/reporting-$type.py
   if [ $? ]; then
     echo "$project reporting $type...OK"
   else
@@ -50,51 +52,28 @@ function report_project()
 
 if [ -z "$1" ]; then
   echo "********************************"
-  echo " Functest reporting "
+  echo " * Static status reporting     *"
   echo "********************************"
-  echo "reporting vIMS..."
-  python ./functest/reporting-vims.py
-  echo "reporting vIMS...OK"
-  sleep 10
-  echo "reporting Tempest..."
-  python ./functest/reporting-tempest.py
-  echo "reporting Tempest...OK"
-  sleep 10
-  echo "reporting status..."
-  python ./functest/reporting-status.py
-  echo "Functest reporting status...OK"
-
-  echo "********************************"
-  echo " Yardstick reporting "
-  echo "********************************"
-  python ./yardstick/reporting-status.py
-  echo "Yardstick reporting status...OK"
+  for i in "${projects[@]}"
+  do
+    report_project $i $i "status"
+    sleep 5
+  done
+  report_project "QTIP" "qtip" "status"
 
-  echo "********************************"
-  echo " Storperf reporting "
-  echo "********************************"
-  python ./storperf/reporting-status.py
-  echo "Storperf reporting status...OK"
 
-  report_project "QTIP" "qtip" "status"
+  echo "Functest reporting vIMS..."
+  report_project "functest" "functest" "vims"
+  echo "reporting vIMS...OK"
+  sleep 5
+  echo "Functest reporting Tempest..."
+  report_project "functest" "functest" "tempest"
+  echo "reporting Tempest...OK"
+  sleep 5
 
 else
   if [ -z "$2" ]; then
     reporting_type="status"
   fi
-  echo "********************************"
-  echo " $project/$reporting_type reporting "
-  echo "********************************"
-  python ./$project/reporting-$reporting_type.py
+  report_project $project $project $reporting_type
 fi
-cp -r display /usr/share/nginx/html
-
-
-# nginx config
-cp /home/opnfv/utils/test/reporting/docker/nginx.conf /etc/nginx/conf.d/
-echo "daemon off;" >> /etc/nginx/nginx.conf
-
-# supervisor config
-cp /home/opnfv/utils/test/reporting/docker/supervisor.conf /etc/supervisor/conf.d/
-
-ln -s /usr/bin/nodejs /usr/bin/node
index 5e315ba..49310d4 100644 (file)
@@ -1,22 +1,19 @@
 [supervisord]
 nodaemon = true
 
-[program:reporting_tornado]
+[program:tornado]
 user = root
-directory = /home/opnfv/utils/test/reporting/api/api
+directory = /home/opnfv/releng/utils/test/reporting/api
 command = python server.py --port=800%(process_num)d
 process_name=%(program_name)s%(process_num)d
 numprocs=4
 numprocs_start=1
-autorestart = true
 
-[program:reporting_nginx]
+[program:nginx]
 user = root
 command = service nginx restart
-autorestart = true
 
-[program:reporting_angular]
+[program:configuration]
 user = root
-directory = /home/opnfv/utils/test/reporting/pages
-command = bash angular.sh
-autorestart = true
+directory = /home/opnfv/releng/utils/test/reporting/pages
+command = bash config.sh
diff --git a/utils/test/reporting/docker/web_server.sh b/utils/test/reporting/docker/web_server.sh
new file mode 100755 (executable)
index 0000000..0dd8df7
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/bash
+cp -r display /usr/share/nginx/html
+
+
+# nginx config
+cp /home/opnfv/releng/utils/test/reporting/docker/nginx.conf /etc/nginx/conf.d/
+echo "daemon off;" >> /etc/nginx/nginx.conf
+
+# supervisor config
+cp /home/opnfv/releng/utils/test/reporting/docker/supervisor.conf /etc/supervisor/conf.d/
+
+# Manage Angular front end
+cd pages && /bin/bash angular.sh
+
diff --git a/utils/test/reporting/docs/_build/.buildinfo b/utils/test/reporting/docs/_build/.buildinfo
new file mode 100644 (file)
index 0000000..6bd6fd6
--- /dev/null
@@ -0,0 +1,4 @@
+# Sphinx build info version 1
+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
+config: 235ce07a48cec983846ad34dfd375b07
+tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/utils/test/reporting/docs/_build/.doctrees/environment.pickle b/utils/test/reporting/docs/_build/.doctrees/environment.pickle
new file mode 100644 (file)
index 0000000..23f59c3
Binary files /dev/null and b/utils/test/reporting/docs/_build/.doctrees/environment.pickle differ
diff --git a/utils/test/reporting/docs/_build/.doctrees/index.doctree b/utils/test/reporting/docs/_build/.doctrees/index.doctree
new file mode 100644 (file)
index 0000000..51e2d5a
Binary files /dev/null and b/utils/test/reporting/docs/_build/.doctrees/index.doctree differ
diff --git a/utils/test/reporting/docs/conf.py b/utils/test/reporting/docs/conf.py
new file mode 100644 (file)
index 0000000..2e70d2b
--- /dev/null
@@ -0,0 +1,341 @@
+# -*- coding: utf-8 -*-
+#
+# OPNFV testing Reporting documentation build configuration file, created by
+# sphinx-quickstart on Mon July 4 10:03:43 2017.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'sphinx.ext.autodoc',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#
+# source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'OPNFV Reporting'
+copyright = u'2017, #opnfv-testperf (chat.freenode.net)'
+author = u'#opnfv-testperf (chat.freenode.net)'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = u'master'
+# The full version, including alpha/beta/rc tags.
+release = u'master'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = 'en'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#
+# today = ''
+#
+# Else, today_fmt is used as the format for a strftime call.
+#
+# today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#
+# default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#
+# add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#
+# add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#
+# show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+# modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+# keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+# html_theme_path = []
+
+# The name for this set of Sphinx documents.
+# "<project> v<release> documentation" by default.
+#
+# html_title = u'OPNFV Functest vmaster'
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#
+# html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#
+# html_logo = None
+
+# The name of an image file (relative to this directory) to use as a favicon of
+# the docs.  This file should be a Windows icon file (.ico) being 16x16 or
+# 32x32 pixels large.
+#
+# html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#
+# html_extra_path = []
+
+# If not None, a 'Last updated on:' timestamp is inserted at every page
+# bottom, using the given strftime format.
+# The empty string is equivalent to '%b %d, %Y'.
+#
+# html_last_updated_fmt = None
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#
+# html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#
+# html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#
+# html_additional_pages = {}
+
+# If false, no module index is generated.
+#
+# html_domain_indices = True
+
+# If false, no index is generated.
+#
+# html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#
+# html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#
+# html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#
+# html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#
+# html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#
+# html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+# html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+#   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
+#   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
+#
+# html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# 'ja' uses this config value.
+# 'zh' user can custom change `jieba` dictionary path.
+#
+# html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#
+# html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'OPNFVreportingdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+     # The paper size ('letterpaper' or 'a4paper').
+     #
+     # 'papersize': 'letterpaper',
+
+     # The font size ('10pt', '11pt' or '12pt').
+     #
+     # 'pointsize': '10pt',
+
+     # Additional stuff for the LaTeX preamble.
+     #
+     # 'preamble': '',
+
+     # Latex figure (float) alignment
+     #
+     # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'OPNFVReporting.tex',
+     u'OPNFV testing Reporting Documentation',
+     u'\\#opnfv-testperf (chat.freenode.net)', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#
+# latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#
+# latex_use_parts = False
+
+# If true, show page references after internal links.
+#
+# latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#
+# latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#
+# latex_appendices = []
+
+# It false, will not define \strong, \code,    itleref, \crossref ... but only
+# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added
+# packages.
+#
+# latex_keep_old_macro_names = True
+
+# If false, no module index is generated.
+#
+# latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'opnfvReporting', u'OPNFV Testing Reporting Documentation',
+     [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#
+# man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'OPNFVReporting', u'OPNFV Testing reporting Documentation',
+     author, 'OPNFVTesting', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#
+# texinfo_appendices = []
+
+# If false, no module index is generated.
+#
+# texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#
+# texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#
+# texinfo_no_detailmenu = False
diff --git a/utils/test/reporting/docs/index.rst b/utils/test/reporting/docs/index.rst
new file mode 100644 (file)
index 0000000..af41876
--- /dev/null
@@ -0,0 +1,16 @@
+Welcome to OPNFV Testing reporting documentation!
+=================================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
index 080f27b..0e00ea6 100755 (executable)
@@ -1,8 +1,3 @@
-: ${SERVER_URL:='http://testresults.opnfv.org/reporting/api'}
-
-echo "var BASE_URL = 'http://${SERVER_URL}/landing-page'" >> app/scripts/app.config.js
-echo "var PROJECT_URL = 'http://${SERVER_URL}'" >> app/scripts/app.config.js
-
 apt-get install -y nodejs
 apt-get install -y npm
 npm install
index f4eb65a..843a623 100644 (file)
     <script src="scripts/controllers/auth.controller.js"></script>
     <script src="scripts/controllers/admin.controller.js"></script>
     <script src="scripts/controllers/main.controller.js"></script>
-    <script src="scripts/app.config.js"></script>
     <script src="scripts/controllers/testvisual.controller.js"></script>
 
     <!-- endbuild -->
 </body>
 
-</html>
\ No newline at end of file
+</html>
index 0f3a17a..8d494c3 100644 (file)
  * Controller of the opnfvdashBoardAngularApp
  */
 angular.module('opnfvApp')
-    .controller('TableController', ['$scope', '$state', '$stateParams', '$http', 'TableFactory', function($scope, $state, $stateParams, $http, TableFactory) {
-
-        $scope.filterlist = [];
-        $scope.selection = [];
-        $scope.statusList = [];
-        $scope.projectList = [];
-        $scope.installerList = [];
-        $scope.versionlist = [];
-        $scope.loopci = [];
-        $scope.time = [];
-        $scope.tableDataAll = {};
-        $scope.tableInfoAll = {};
-        $scope.scenario = {};
-
-        $scope.VersionConfig = {
-            create: true,
-            valueField: 'title',
-            labelField: 'title',
-            delimiter: '|',
-            maxItems: 1,
-            placeholder: 'Version',
-            onChange: function(value) {
-                checkElementArrayValue($scope.selection, $scope.VersionOption);
-                $scope.selection.push(value);
-                // console.log($scope.selection);
-                getScenarioData();
-
-            }
-        }
-
-        $scope.LoopConfig = {
-            create: true,
-            valueField: 'title',
-            labelField: 'title',
-            delimiter: '|',
-            maxItems: 1,
-            placeholder: 'Loop',
-            onChange: function(value) {
-                checkElementArrayValue($scope.selection, $scope.LoopOption);
-                $scope.selection.push(value);
-                // console.log($scope.selection);
-                getScenarioData();
-
-            }
-        }
-
-        $scope.TimeConfig = {
-            create: true,
-            valueField: 'title',
-            labelField: 'title',
-            delimiter: '|',
-            maxItems: 1,
-            placeholder: 'Time',
-            onChange: function(value) {
-                checkElementArrayValue($scope.selection, $scope.TimeOption);
-                $scope.selection.push(value);
-                // console.log($scope.selection)
-                getScenarioData();
-
+    .controller('TableController', ['$scope', '$state', '$stateParams', '$http', 'TableFactory', '$timeout',
+        function($scope, $state, $stateParams, $http, TableFactory, $timeout) {
+
+            init();
+
+            function init() {
+                $scope.filterlist = [];
+                $scope.selection = [];
+
+                $scope.statusList = [];
+                $scope.projectList = [];
+                $scope.installerList = [];
+                $scope.versionlist = [];
+                $scope.loopList = [];
+                $scope.timeList = [];
+
+                $scope.selectStatus = [];
+                $scope.selectProjects = [];
+                $scope.selectInstallers = [];
+                $scope.selectVersion = null;
+                $scope.selectLoop = null;
+                $scope.selectTime = null;
+
+                $scope.statusClicked = false;
+                $scope.installerClicked = false;
+                $scope.projectClicked = false;
+
+                $scope.scenarios = {};
+
+                $scope.VersionConfig = {
+                    create: true,
+                    valueField: 'title',
+                    labelField: 'title',
+                    delimiter: '|',
+                    maxItems: 1,
+                    placeholder: 'Version',
+                    onChange: function(value) {
+                        $scope.selectVersion = value;
+
+                        getScenarioData();
 
-            }
-        }
-
-
-        init();
-
-        function init() {
-            $scope.toggleSelection = toggleSelection;
-            getScenarioData();
-            // radioSetting();
-            getFilters();
-        }
-
-        function getFilters() {
-            TableFactory.getFilter().get({
-
-
-            }).$promise.then(function(response) {
-                if (response != null) {
-                    $scope.statusList = response.filters.status;
-                    $scope.projectList = response.filters.projects;
-                    $scope.installerList = response.filters.installers;
-                    $scope.versionlist = response.filters.version;
-                    $scope.loopci = response.filters.loops;
-                    $scope.time = response.filters.time;
-
-                    $scope.statusListString = $scope.statusList.toString();
-                    $scope.projectListString = $scope.projectList.toString();
-                    $scope.installerListString = $scope.installerList.toString();
-                    $scope.VersionSelected = $scope.versionlist[1];
-                    $scope.LoopCiSelected = $scope.loopci[0];
-                    $scope.TimeSelected = $scope.time[0];
-                    radioSetting($scope.versionlist, $scope.loopci, $scope.time);
-
-                } else {
-                    alert("网络错误");
-                }
-            })
-        }
-
-        function getScenarioData() {
-
-            var utl = BASE_URL + '/scenarios';
-            var data = {
-                'status': ['success', 'danger', 'warning'],
-                'projects': ['functest', 'yardstick'],
-                'installers': ['apex', 'compass', 'fuel', 'joid'],
-                'version': $scope.VersionSelected,
-                'loops': $scope.LoopCiSelected,
-                'time': $scope.TimeSelected
-            };
-            var config = {
-                headers: {
-                    'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
-                }
-            }
-            $http.post(utl, data, config).then(function(response) {
-                if (response.status == 200) {
-                    $scope.scenario = response.data;
-                    constructJson();
-                }
-            })
-        }
-
-        //construct json 
-        function constructJson() {
-
-            var colspan;
-            var InstallerData;
-            var projectsInfo;
-            $scope.tableDataAll["scenario"] = [];
-
-
-            for (var item in $scope.scenario.scenarios) {
-
-                var headData = Object.keys($scope.scenario.scenarios[item].installers).sort();
-                var scenarioStatus = $scope.scenario.scenarios[item].status;
-                var scenarioStatusDisplay;
-                if (scenarioStatus == "success") {
-                    scenarioStatusDisplay = "navy";
-                } else if (scenarioStatus == "danger") {
-                    scenarioStatusDisplay = "danger";
-                } else if (scenarioStatus == "warning") {
-                    scenarioStatusDisplay = "warning";
+                    }
                 }
 
-                InstallerData = headData;
-                var projectData = [];
-                var datadisplay = [];
-                var projects = [];
+                $scope.LoopConfig = {
+                    create: true,
+                    valueField: 'title',
+                    labelField: 'title',
+                    delimiter: '|',
+                    maxItems: 1,
+                    placeholder: 'Loop',
+                    onChange: function(value) {
+                        $scope.selectLoop = value;
 
-                for (var j = 0; j < headData.length; j++) {
+                        getScenarioData();
 
-                    projectData.push($scope.scenario.scenarios[item].installers[headData[j]]);
+                    }
                 }
-                for (var j = 0; j < projectData.length; j++) {
-
-                    for (var k = 0; k < projectData[j].length; k++) {
-                        projects.push(projectData[j][k].project);
-                        var temArray = [];
-                        if (projectData[j][k].score == null) {
-                            temArray.push("null");
-                            temArray.push(projectData[j][k].project);
-                            temArray.push(headData[j]);
-                        } else {
-                            temArray.push(projectData[j][k].score);
-                            temArray.push(projectData[j][k].project);
-                            temArray.push(headData[j]);
-                        }
-
-
-                        if (projectData[j][k].status == "platinium") {
-                            temArray.push("primary");
-                            temArray.push("P");
-                        } else if (projectData[j][k].status == "gold") {
-                            temArray.push("danger");
-                            temArray.push("G");
-                        } else if (projectData[j][k].status == "silver") {
-                            temArray.push("warning");
-                            temArray.push("S");
-                        } else if (projectData[j][k].status == null) {
-                            temArray.push("null");
-                        }
-
-                        datadisplay.push(temArray);
 
+                $scope.TimeConfig = {
+                    create: true,
+                    valueField: 'title',
+                    labelField: 'title',
+                    delimiter: '|',
+                    maxItems: 1,
+                    placeholder: 'Time',
+                    onChange: function(value) {
+                        $scope.selectTime = value;
+
+                        getScenarioData();
                     }
-
                 }
 
-                colspan = projects.length / headData.length;
-
-                var tabledata = {
-                    scenarioName: item,
-                    Installer: InstallerData,
-                    projectData: projectData,
-                    projects: projects,
-                    datadisplay: datadisplay,
-                    colspan: colspan,
-                    status: scenarioStatus,
-                    statusDisplay: scenarioStatusDisplay
-                };
-
-                JSON.stringify(tabledata);
-                $scope.tableDataAll.scenario.push(tabledata);
-
-                // console.log(tabledata);
-
+                getFilters();
             }
 
+            function getFilters() {
+                TableFactory.getFilter().get({
+                }).$promise.then(function(response) {
+                    if (response != null) {
+                        $scope.statusList = response.filters.status;
+                        $scope.projectList = response.filters.projects;
+                        $scope.installerList = response.filters.installers;
+                        $scope.versionList = toSelectList(response.filters.version);
+                        $scope.loopList = toSelectList(response.filters.loops);
+                        $scope.timeList = toSelectList(response.filters.time);
+
+                        $scope.selectStatus = copy($scope.statusList);
+                        $scope.selectInstallers = copy($scope.installerList);
+                        $scope.selectProjects = copy($scope.projectList);
+                        $scope.selectVersion = response.filters.version[0];
+                        $scope.selectLoop = response.filters.loops[0];
+                        $scope.selectTime = response.filters.time[0];
+
+                        getScenarioData();
+
+                    } else {
+                    }
+                });
+            }
 
-            projectsInfo = $scope.tableDataAll.scenario[0].projects;
-
-            var tempHeadData = [];
-
-            for (var i = 0; i < InstallerData.length; i++) {
-                for (var j = 0; j < colspan; j++) {
-                    tempHeadData.push(InstallerData[i]);
-                }
+            function toSelectList(arr){
+                var tempList = [];
+                angular.forEach(arr, function(ele){
+                    tempList.push({'title': ele});
+                });
+                return tempList;
             }
 
-            //console.log(tempHeadData);
+            function copy(arr){
+                var tempList = [];
+                angular.forEach(arr, function(ele){
+                    tempList.push(ele);
+                });
+                return tempList;
+            }
 
-            var projectsInfoAll = [];
+            function getScenarioData() {
 
-            for (var i = 0; i < projectsInfo.length; i++) {
-                var tempA = [];
-                tempA.push(projectsInfo[i]);
-                tempA.push(tempHeadData[i]);
-                projectsInfoAll.push(tempA);
+                var data = {
+                    'status': $scope.selectStatus,
+                    'projects': $scope.selectProjects,
+                    'installers': $scope.selectInstallers,
+                    'version': $scope.selectVersion,
+                    'loops': $scope.selectLoop,
+                    'time': $scope.selectTime
+                };
 
-            }
-            //console.log(projectsInfoAll);
+                TableFactory.getScenario(data).then(function(response) {
+                    if (response.status == 200) {
+                        $scope.scenarios = response.data.scenarios;
+                        getScenario();
+                    }
 
-            $scope.tableDataAll["colspan"] = colspan;
-            $scope.tableDataAll["Installer"] = InstallerData;
-            $scope.tableDataAll["Projects"] = projectsInfoAll;
+                }, function(error) {
+                });
 
-            // console.log($scope.tableDataAll);
-            $scope.colspan = $scope.tableDataAll.colspan;
+            }
 
-        }
+            function getScenario(){
 
-        //get json element size
-        function getSize(jsondata) {
-            var size = 0;
-            for (var item in jsondata) {
-                size++;
+                $scope.project_row = [];
+                angular.forEach($scope.selectInstallers, function(installer){
+                    angular.forEach($scope.selectProjects, function(project){
+                        var temp = {
+                            'installer': installer,
+                            'project': project
+                        }
+                        $scope.project_row.push(temp);
+
+                    });
+                });
+
+
+                $scope.scenario_rows = [];
+                angular.forEach($scope.scenarios, function(scenario, name){
+                    var scenario_row = {
+                        'name': null,
+                        'status': null,
+                        'statusDisplay': null,
+                        'datadisplay': [],
+                    };
+                    scenario_row.name = name;
+                    scenario_row.status = scenario.status;
+
+                    var scenarioStatusDisplay;
+                    if (scenario.status == "success") {
+                        scenarioStatusDisplay = "navy";
+                    } else if (scenario.status == "danger") {
+                        scenarioStatusDisplay = "danger";
+                    } else if (scenario.status == "warning") {
+                        scenarioStatusDisplay = "warning";
+                    }
+                    scenario_row.statusDisplay = scenarioStatusDisplay;
+
+                    angular.forEach($scope.selectInstallers, function(installer){
+                        angular.forEach($scope.selectProjects, function(project){
+                            var datadisplay = {
+                                'installer': null,
+                                'project': null,
+                                'value': null,
+                                'label': null,
+                                'label_value': null
+                            };
+                            datadisplay.installer = installer;
+                            datadisplay.project = project;
+                            datadisplay.value = scenario.installers[installer][project].score;
+
+                            var single_status = scenario.installers[installer][project].status;
+                            if (single_status == "platinium") {
+                                datadisplay.label = 'primary';
+                                datadisplay.label_value = 'P';
+                            } else if (single_status == "gold") {
+                                datadisplay.label = 'danger';
+                                datadisplay.label_value = 'G';
+                            } else if (single_status == "silver") {
+                                datadisplay.label = 'warning';
+                                datadisplay.label_value = 'S';
+                            } else if (single_status == null) {
+                            }
+                            scenario_row.datadisplay.push(datadisplay);
+
+                        });
+                    });
+                    $scope.scenario_rows.push(scenario_row);
+                });
             }
-            return size;
-        }
 
-        $scope.colspan = $scope.tableDataAll.colspan;
-        // console.log($scope.colspan);
 
-
-        //find all same element index 
-        function getSameElementIndex(array, element) {
-            var indices = [];
-            var idx = array.indexOf(element);
-            while (idx != -1) {
-                indices.push(idx);
-                idx = array.indexOf(element, idx + 1);
+            function clickBase(eleList, ele){
+                var idx = eleList.indexOf(ele);
+                if(idx > -1){
+                    eleList.splice(idx, 1);
+                }else{
+                    eleList.push(ele);
+                }
             }
-            //return indices;
-            var result = { element: element, index: indices };
-            JSON.stringify(result);
-            return result;
-        }
 
-        //delete element in array
-        function deletElement(array, index) {
-            array.splice(index, 1);
+            $scope.clickStatus = function(status){
+                if($scope.selectStatus.length == $scope.statusList.length && $scope.statusClicked == false){
+                    $scope.selectStatus = [];
+                    $scope.statusClicked = true;
+                }
 
-        }
+                clickBase($scope.selectStatus, status);
 
-        function radioSetting(array1, array2, array3) {
-            var tempVersion = [];
-            var tempLoop = [];
-            var tempTime = [];
-            for (var i = 0; i < array1.length; i++) {
-                var temp = {
-                    title: array1[i]
-                };
-                tempVersion.push(temp);
-            }
-            for (var i = 0; i < array2.length; i++) {
-                var temp = {
-                    title: array2[i]
-                };
-                tempLoop.push(temp);
-            }
-            for (var i = 0; i < array3.length; i++) {
-                var temp = {
-                    title: array3[i]
-                };
-                tempTime.push(temp);
-            }
-            $scope.VersionOption = tempVersion;
-            $scope.LoopOption = tempLoop;
-            $scope.TimeOption = tempTime;
-        }
-
-        //remove element in the array
-        function removeArrayValue(arr, value) {
-            for (var i = 0; i < arr.length; i++) {
-                if (arr[i] == value) {
-                    arr.splice(i, 1);
-                    break;
+                if($scope.selectStatus.length == 0 && $scope.statusClicked == true){
+                    $scope.selectStatus = copy($scope.statusList);
+                    $scope.statusClicked = false;
                 }
+
+                getScenarioData();
             }
-        }
 
-        //check if exist element
-        function checkElementArrayValue(arrayA, arrayB) {
-            for (var i = 0; i < arrayB.length; i++) {
-                if (arrayA.indexOf(arrayB[i].title) > -1) {
-                    removeArrayValue(arrayA, arrayB[i].title);
+            $scope.clickInstaller = function(installer){
+                if($scope.selectInstallers.length == $scope.installerList.length && $scope.installerClicked == false){
+                    $scope.selectInstallers = [];
+                    $scope.installerClicked = true;
                 }
-            }
-        }
 
-        function toggleSelection(status) {
-            var idx = $scope.selection.indexOf(status);
+                clickBase($scope.selectInstallers, installer);
+
+                if($scope.selectInstallers.length == 0 && $scope.installerClicked == true){
+                    $scope.selectInstallers = copy($scope.installerList);
+                    $scope.installerClicked = false;
+                }
 
-            if (idx > -1) {
-                $scope.selection.splice(idx, 1);
-                filterData($scope.selection)
-            } else {
-                $scope.selection.push(status);
-                filterData($scope.selection)
+                getScenarioData();
             }
-            // console.log($scope.selection);
 
-        }
+            $scope.clickProject = function(project){
+                if($scope.selectProjects.length == $scope.projectList.length && $scope.projectClicked == false){
+                    $scope.selectProjects = [];
+                    $scope.projectClicked = true;
+                }
 
-        //filter function
-        function filterData(selection) {
+                clickBase($scope.selectProjects, project);
 
-            $scope.selectInstallers = [];
-            $scope.selectProjects = [];
-            $scope.selectStatus = [];
-            for (var i = 0; i < selection.length; i++) {
-                if ($scope.statusListString.indexOf(selection[i]) > -1) {
-                    $scope.selectStatus.push(selection[i]);
-                }
-                if ($scope.projectListString.indexOf(selection[i]) > -1) {
-                    $scope.selectProjects.push(selection[i]);
-                }
-                if ($scope.installerListString.indexOf(selection[i]) > -1) {
-                    $scope.selectInstallers.push(selection[i]);
+                if($scope.selectProjects.length == 0 && $scope.projectClicked == true){
+                    $scope.selectProjects = copy($scope.projectList);
+                    $scope.projectClicked = false;
                 }
-            }
-
-            $scope.colspan = $scope.selectProjects.length;
-            //when some selection is empty, we set it full
-            if ($scope.selectInstallers.length == 0) {
-                $scope.selectInstallers = $scope.installerList;
 
+                getScenarioData();
             }
-            if ($scope.selectProjects.length == 0) {
-                $scope.selectProjects = $scope.projectList;
-                $scope.colspan = $scope.tableDataAll.colspan;
-            }
-            if ($scope.selectStatus.length == 0) {
-                $scope.selectStatus = $scope.statusList
-            }
-
-            // console.log($scope.selectStatus);
-            // console.log($scope.selectProjects);
 
         }
-
-
-    }]);
\ No newline at end of file
+    ]);
index ae51e4a..894e10f 100644 (file)
@@ -41,25 +41,18 @@ angular.module('opnfvApp')
                 $scope.tableData = null;
                 $scope.modalName = name;
 
-                var url = PROJECT_URL + '/projects/' + name + '/cases';
-
-                var config = {
-                    headers: {
-                        'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
-                    }
-                }
-                $http.get(url, config).then(function(response) {
+                TableFactory.getProjectTestCases(name).then(function(response) {
                     if (response.status == 200) {
                         $scope.tableData = response.data;
 
                         $scope.tableData = constructObjectArray($scope.tableData);
                         console.log($scope.tableData);
                         $loading.finish('Key');
-
-
-
                     }
+                }, function(error) {
+
                 })
+
             }
 
             //construct key value for tableData
index 2a8cbd0..e715c5c 100644 (file)
@@ -4,45 +4,67 @@
  * get data factory
  */
 angular.module('opnfvApp')
-    .factory('TableFactory', function($resource, $rootScope) {
+    .factory('TableFactory', function($resource, $rootScope, $http) {
+
+        var BASE_URL = 'http://testresults.opnfv.org/reporting2';
+        $.ajax({
+          url: 'config.json',
+          async: false,
+          dataType: 'json',
+          success: function (response) {
+              BASE_URL = response.url;
+          },
+          error: function (response){
+              alert('fail to get api url, using default: http://testresults.opnfv.org/reporting2')
+          }
+        });
 
         return {
             getFilter: function() {
-                return $resource(BASE_URL + '/filters', {}, {
+                return $resource(BASE_URL + '/landing-page/filters', {}, {
                     'get': {
                         method: 'GET',
 
                     }
                 });
             },
-            getScenario: function() {
-                return $resource(BASE_URL + '/scenarios', {}, {
-                    'post': {
-                        method: 'POST',
+            getScenario: function(data) {
+
+                var config = {
+                    headers: {
+                        'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
                     }
-                })
+                }
+
+                return $http.post(BASE_URL + '/landing-page/scenarios', data, config);
             },
+
+
             getProjectUrl: function() {
-                return $resource(PROJECT_URL + '/projects-page/projects', {}, {
+                return $resource(BASE_URL + '/projects-page/projects', {}, {
                     'get': {
                         method: 'GET'
                     }
                 })
             },
-            getProjectTestCases: function() {
-                return $resource(PROJECT_URL + '/projects/:project/cases', { project: '@project' }, {
-                    'get': {
-                        method: 'GET'
+            getProjectTestCases: function(name) {
+                var config = {
+                    headers: {
+                        'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
                     }
-                })
+                };
+                return $http.get(BASE_URL + '/projects/' + name + '/cases', {}, config)
+
+
             },
             getProjectTestCaseDetail: function() {
-                return $resource(PROJECT_URL + '/projects/:project/cases/:testcase', { project: '@project', testcase: '@testcase' }, {
+                return $resource(BASE_URL + '/projects/:project/cases/:testcase', { project: '@project', testcase: '@testcase' }, {
                     'get': {
 
                         method: 'GET'
                     }
                 })
             }
+
         };
-    });
\ No newline at end of file
+    });
index f504bd7..a33c483 100644 (file)
@@ -29,9 +29,9 @@
                     <div class=" col-md-12" data-toggle="buttons" aria-pressed="false">
 
                         <label> Status </label> &nbsp;&nbsp; &nbsp;
-                        <label class="btn btn-outline btn-success btn-sm" style="height:25px; margin-right: 5px;" ng-repeat="status in statusList" value={{status}} ng-checked="selection.indexOf(status)>-1" ng-click="toggleSelection(status)">
+                        <label class="btn btn-outline btn-success btn-sm" style="height:25px; margin-right: 5px;" ng-repeat="status in statusList" value={{status}} ng-checked="selectStatus.indexOf(status)>-1" ng-click="clickStatus(status)">
                               <input type="checkbox"  disabled="disabled" > {{status}}
-                            
+
                           </label>
                     </div>
 
@@ -39,7 +39,7 @@
 
                     <div class=" col-md-12" data-toggle="buttons">
                         <label> Projects </label> &nbsp;
-                        <label class="btn btn-outline btn-success btn-sm " style="height:25px;margin-right: 5px;" ng-repeat="project in projectList" value={{project}} ng-checked="selection.indexOf(project)>-1" ng-click="toggleSelection(project)">
+                        <label class="btn btn-outline btn-success btn-sm " style="height:25px;margin-right: 5px;" ng-repeat="project in projectList" value={{project}} ng-checked="selectProjects.indexOf(project)>-1" ng-click="clickProject(project)">
                             <input type="checkbox" disabled="disabled"> {{project}}
                         </label>
 
@@ -47,7 +47,7 @@
                     <hr class="myhr">
                     <div class=" col-md-12" data-toggle="buttons">
                         <label> Installers </label>
-                        <label class="btn btn-outline btn-success btn-sm" style="height:25px;margin-right: 5px;" ng-repeat="installer in installerList" value={{installer}} ng-checked="selection.indexOf(installer)>-1" ng-click="toggleSelection(installer)">
+                        <label class="btn btn-outline btn-success btn-sm" style="height:25px;margin-right: 5px;" ng-repeat="installer in installerList" value={{installer}} ng-checked="selectInstallers.indexOf(installer)>-1" ng-click="clickInstaller(installer)">
                             <input type="checkbox" disabled="disabled"> {{installer}}
                             </label>
                     </div>
 
 
                     <div class=" col-md-1" style="margin-top:5px;margin-right: 5px;">
-                        <selectize options="VersionOption" ng-model="VersionSelected" config="VersionConfig"></selectize>
+                        <selectize options="versionList" ng-model="selectVersion" config="VersionConfig"></selectize>
 
                     </div>
 
                     <div class=" col-md-1" style="margin-top:5px;margin-right: 5px;">
-                        <selectize options="LoopOption" ng-model="LoopCiSelected" config="LoopConfig"></selectize>
+                        <selectize options="loopList" ng-model="selectLoop" config="LoopConfig"></selectize>
 
                     </div>
 
                     <div class=" col-md-1" style="margin-top:5px;margin-right: 5px;">
-                        <selectize options="TimeOption" ng-model="TimeSelected" config="TimeConfig"></selectize>
+                        <selectize options="timeList" ng-model="selectTime" config="TimeConfig"></selectize>
                     </div>
                 </div>
                 <div class="table-responsive">
                         <thead class="thead">
                             <tr>
                                 <th>Scenario </th>
-                                <th colspan={{colspan}} ng-show="selectInstallers.indexOf(key)!=-1" value={{key}} ng-repeat="key in tableDataAll.Installer"><a href="notfound.html">{{key}}</a> </th>
+                                <th colspan={{selectProjects.length}} ng-show="selectInstallers.indexOf(key)!=-1" value={{key}} ng-repeat="key in selectInstallers"><a href="notfound.html">{{key}}</a> </th>
                             </tr>
 
                             <tr>
 
                                 <td></td>
-                                <td ng-show="selectProjects.indexOf(project[0])!=-1 && selectInstallers.indexOf(project[1])!=-1" ng-repeat="project in tableDataAll.Projects track by $index" data={{project[1]}} value={{project[0]}}>{{project[0]}}</td>
+                                <td ng-show="selectProjects.indexOf(project.project)!=-1 && selectInstallers.indexOf(project.installer)!=-1" ng-repeat="project in project_row track by $index" data={{project.installer}} value={{project.project}}>{{ project.project }}</td>
 
                             </tr>
                         </thead>
                         <tbody class="tbody">
-                            <tr ng-repeat="scenario in tableDataAll.scenario" ng-show="selectStatus.indexOf(scenario.status)!=-1">
+                            <tr ng-repeat="scenario in scenario_rows" ng-show="selectStatus.indexOf(scenario.status)!=-1">
 
-                                <td nowrap="nowrap" data={{scenario.status}}><span class="fa fa-circle text-{{scenario.statusDisplay}}"></span> <a href="notfound.html">{{scenario.scenarioName}}</a> </td>
+                                <td nowrap="nowrap" data={{scenario.status}}><span class="fa fa-circle text-{{scenario.statusDisplay}}"></span> <a href="notfound.html">{{scenario.name}}</a> </td>
 
                                 <!--<td style="background-color:#e7eaec" align="justify" ng-if="data[0]=='Not Support'" ng-repeat="data in scenario.datadisplay track by $index" data={{data[1]}} value={{data[2]}}></td>-->
 
-                                <td nowrap="nowrap" ng-show="selectInstallers.indexOf(data[2])!=-1 && selectProjects.indexOf(data[1])!=-1" ng-repeat="data in scenario.datadisplay track by $index" data={{data[1]}} value={{data[2]}} class={{data[0]}}>
-                                    <span class="label label-{{data[3]}}">{{data[4]}}</a></span> {{data[0]}}</td>
+                                <td nowrap="nowrap" ng-show="selectInstallers.indexOf(data.installer)!=-1 && selectProjects.indexOf(data.project)!=-1" ng-repeat="data in scenario.datadisplay track by $index" data={{data.project}} value={{data.installer}} class={{data.value}}>
+                                    <span class="label label-{{data.label}}">{{data.label_value}}</a></span> {{data.value}}</td>
 
 
                             </tr>
         </div>
     </div>
 
-</section>
\ No newline at end of file
+</section>
diff --git a/utils/test/reporting/pages/config.sh b/utils/test/reporting/pages/config.sh
new file mode 100755 (executable)
index 0000000..62aa16f
--- /dev/null
@@ -0,0 +1,3 @@
+: ${SERVER_URL:='testresults.opnfv.org/testing/api'}
+
+echo "{\"url\": \"http://${SERVER_URL}\"}" > dist/config.json
diff --git a/utils/test/reporting/reporting/bottlenecks/reporting-status.py b/utils/test/reporting/reporting/bottlenecks/reporting-status.py
new file mode 100644 (file)
index 0000000..8966d06
--- /dev/null
@@ -0,0 +1,145 @@
+#!/usr/bin/python
+#
+# This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+import datetime
+import os
+
+import jinja2
+
+import reporting.utils.reporting_utils as rp_utils
+import reporting.utils.scenarioResult as sr
+
+INSTALLERS = rp_utils.get_config('general.installers')
+VERSIONS = rp_utils.get_config('general.versions')
+PERIOD = rp_utils.get_config('general.period')
+
+# Logger
+LOGGER = rp_utils.getLogger("Bottlenecks-Status")
+reportingDate = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
+
+LOGGER.info("*******************************************")
+LOGGER.info("*   Generating reporting scenario status  *")
+LOGGER.info("*   Data retention = %s days              *", PERIOD)
+LOGGER.info("*                                         *")
+LOGGER.info("*******************************************")
+
+# retrieve the list of bottlenecks tests
+BOTTLENECKS_TESTS = rp_utils.get_config('bottlenecks.test_list')
+LOGGER.info("Bottlenecks tests: %s", BOTTLENECKS_TESTS)
+
+# For all the versions
+for version in VERSIONS:
+    # For all the installers
+    for installer in INSTALLERS:
+        # get scenarios results data
+        scenario_results = rp_utils.getScenarios("bottlenecks",
+                                                 "posca_factor_ping",
+                                                 installer,
+                                                 version)
+        LOGGER.info("scenario_results: %s", scenario_results)
+
+        scenario_stats = rp_utils.getScenarioStats(scenario_results)
+        LOGGER.info("scenario_stats: %s", scenario_stats)
+        items = {}
+        scenario_result_criteria = {}
+
+        # From each scenarios get results list
+        for s, s_result in scenario_results.items():
+            LOGGER.info("---------------------------------")
+            LOGGER.info("installer %s, version %s, scenario %s", installer,
+                        version, s)
+            ten_criteria = len(s_result)
+
+            ten_score = 0
+            for v in s_result:
+                if "PASS" in v['criteria']:
+                    ten_score += 1
+
+            LOGGER.info("ten_score: %s / %s", (ten_score, ten_criteria))
+
+            four_score = 0
+            try:
+                LASTEST_TESTS = rp_utils.get_config(
+                    'general.nb_iteration_tests_success_criteria')
+                s_result.sort(key=lambda x: x['start_date'])
+                four_result = s_result[-LASTEST_TESTS:]
+                LOGGER.debug("four_result: {}".format(four_result))
+                LOGGER.debug("LASTEST_TESTS: {}".format(LASTEST_TESTS))
+                # logger.debug("four_result: {}".format(four_result))
+                four_criteria = len(four_result)
+                for v in four_result:
+                    if "PASS" in v['criteria']:
+                        four_score += 1
+                LOGGER.info("4 Score: %s / %s ", (four_score,
+                                                  four_criteria))
+            except Exception:
+                LOGGER.error("Impossible to retrieve the four_score")
+
+            try:
+                s_status = (four_score * 100) / four_criteria
+            except Exception:
+                s_status = 0
+            LOGGER.info("Score percent = %s", str(s_status))
+            s_four_score = str(four_score) + '/' + str(four_criteria)
+            s_ten_score = str(ten_score) + '/' + str(ten_criteria)
+            s_score_percent = str(s_status)
+
+            LOGGER.debug(" s_status: %s", s_status)
+            if s_status == 100:
+                LOGGER.info(">>>>> scenario OK, save the information")
+            else:
+                LOGGER.info(">>>> scenario not OK, last 4 iterations = %s, \
+                             last 10 days = %s", (s_four_score, s_ten_score))
+
+            s_url = ""
+            if len(s_result) > 0:
+                build_tag = s_result[len(s_result)-1]['build_tag']
+                LOGGER.debug("Build tag: %s", build_tag)
+                s_url = s_url = rp_utils.getJenkinsUrl(build_tag)
+                LOGGER.info("last jenkins url: %s", s_url)
+
+            # Save daily results in a file
+            path_validation_file = ("./display/" + version +
+                                    "/bottlenecks/scenario_history.txt")
+
+            if not os.path.exists(path_validation_file):
+                with open(path_validation_file, 'w') as f:
+                    info = 'date,scenario,installer,details,score\n'
+                    f.write(info)
+
+            with open(path_validation_file, "a") as f:
+                info = (reportingDate + "," + s + "," + installer +
+                        "," + s_ten_score + "," +
+                        str(s_score_percent) + "\n")
+                f.write(info)
+
+            scenario_result_criteria[s] = sr.ScenarioResult(s_status,
+                                                            s_four_score,
+                                                            s_ten_score,
+                                                            s_score_percent,
+                                                            s_url)
+
+            LOGGER.info("--------------------------")
+
+        templateLoader = jinja2.FileSystemLoader(".")
+        templateEnv = jinja2.Environment(loader=templateLoader,
+                                         autoescape=True)
+
+        TEMPLATE_FILE = ("./reporting/bottlenecks/template"
+                         "/index-status-tmpl.html")
+        template = templateEnv.get_template(TEMPLATE_FILE)
+
+        outputText = template.render(scenario_results=scenario_result_criteria,
+                                     installer=installer,
+                                     period=PERIOD,
+                                     version=version,
+                                     date=reportingDate)
+
+        with open("./display/" + version +
+                  "/bottlenecks/status-" + installer + ".html", "wb") as fh:
+            fh.write(outputText)
diff --git a/utils/test/reporting/reporting/bottlenecks/template/index-status-tmpl.html b/utils/test/reporting/reporting/bottlenecks/template/index-status-tmpl.html
new file mode 100644 (file)
index 0000000..c4497ac
--- /dev/null
@@ -0,0 +1,114 @@
+ <html>
+  <head>
+    <meta charset="utf-8">
+    <!-- Bootstrap core CSS -->
+    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
+    <link href="../../css/default.css" rel="stylesheet">
+    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
+    <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script>
+    <script type="text/javascript" src="../../js/gauge.js"></script>
+    <script type="text/javascript" src="../../js/trend.js"></script>
+    <script>
+        function onDocumentReady() {
+            // Gauge management
+            {% for scenario in scenario_results.keys() -%}
+            var gaugeScenario{{loop.index}} = gauge('#gaugeScenario{{loop.index}}');
+            {%- endfor %}
+            // assign success rate to the gauge
+            function updateReadings() {
+                {% for scenario in scenario_results.keys() -%}
+                 gaugeScenario{{loop.index}}.update({{scenario_results[scenario].getScorePercent()}});
+                 {%- endfor %}
+            }
+            updateReadings();
+        }
+
+        // trend line management
+        d3.csv("./scenario_history.txt", function(data) {
+            // ***************************************
+            // Create the trend line
+            {% for scenario in scenario_results.keys() -%}
+            // for scenario {{scenario}}
+            // Filter results
+                var trend{{loop.index}} = data.filter(function(row) {
+                    return row["scenario"]=="{{scenario}}" && row["installer"]=="{{installer}}";
+                })
+            // Parse the date
+            trend{{loop.index}}.forEach(function(d) {
+                d.date = parseDate(d.date);
+                d.score = +d.score
+            });
+            // Draw the trend line
+            var mytrend = trend("#trend_svg{{loop.index}}",trend{{loop.index}})
+            // ****************************************
+            {%- endfor %}
+        });
+        if ( !window.isLoaded ) {
+            window.addEventListener("load", function() {
+            onDocumentReady();
+            }, false);
+        } else {
+            onDocumentReady();
+        }
+    </script>
+    <script type="text/javascript">
+    $(document).ready(function (){
+        $(".btn-more").click(function() {
+            $(this).hide();
+            $(this).parent().find(".panel-default").show();
+        });
+    })
+    </script>
+  </head>
+    <body>
+    <div class="container">
+      <div class="masthead">
+          <h3 class="text-muted">Bottlenecks status page ({{version}}, {{date}})</h3>
+        <nav>
+          <ul class="nav nav-justified">
+            <li class="active"><a href="http://testresults.opnfv.org/reporting/index.html">Home</a></li>
+            <li><a href="status-apex.html">Apex</a></li>
+            <li><a href="status-compass.html">Compass</a></li>
+            <li><a href="status-fuel.html">Fuel</a></li>
+            <li><a href="status-joid.html">Joid</a></li>
+          </ul>
+        </nav>
+      </div>
+<div class="row">
+    <div class="col-md-1"></div>
+    <div class="col-md-10">
+        <div class="page-header">
+            <h2>{{installer}}</h2>
+        </div>
+        <div><h1>Reported values represent the percentage of completed
+
+          CI tests (posca_factor_ping) during the reporting period, where results
+
+          were communicated to the Test Database.</h1></div>
+        <div class="scenario-overview">
+            <div class="panel-heading"><h4><b>List of last scenarios ({{version}}) run over the last {{period}} days </b></h4></div>
+                <table class="table">
+                    <tr>
+                        <th width="40%">Scenario</th>
+                        <th width="20%">Status</th>
+                        <th width="20%">Trend</th>
+                        <th width="10%">Last 4 Iterations</th>
+                        <th width="10%">Last 10 Days</th>
+                    </tr>
+                        {% for scenario,result in scenario_results.iteritems() -%}
+                            <tr class="tr-ok">
+                                <td><a href="{{scenario_results[scenario].getLastUrl()}}">{{scenario}}</a></td>
+                                <td><div id="gaugeScenario{{loop.index}}"></div></td>
+                                <td><div id="trend_svg{{loop.index}}"></div></td>
+                                <td>{{scenario_results[scenario].getFourDaysScore()}}</td>
+                                <td>{{scenario_results[scenario].getTenDaysScore()}}</td>
+                            </tr>
+                        {%- endfor %}
+                </table>
+        </div>
+
+
+    </div>
+    <div class="col-md-1"></div>
+</div>
@@ -7,16 +7,19 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 #
 import datetime
-import jinja2
 import os
 import sys
 import time
 
+import jinja2
+
 import testCase as tc
 import scenarioResult as sr
+import reporting.utils.reporting_utils as rp_utils
 
-# manage conf
-import utils.reporting_utils as rp_utils
+"""
+Functest reporting status
+"""
 
 # Logger
 logger = rp_utils.getLogger("Functest-Status")
@@ -104,7 +107,8 @@ for version in versions:
     for installer in installers:
 
         # get scenarios
-        scenario_results = rp_utils.getScenarios(healthcheck,
+        scenario_results = rp_utils.getScenarios("functest",
+                                                 "connection_check",
                                                  installer,
                                                  version)
         # get nb of supported architecture (x86, aarch64)
@@ -124,7 +128,7 @@ for version in versions:
             # in case of more than 1 architecture supported
             # precise the architecture
             installer_display = installer
-            if (len(architectures) > 1):
+            if "fuel" in installer:
                 installer_display = installer + "@" + architecture
 
             # For all the scenarios get results
@@ -217,7 +221,7 @@ for version in versions:
                                 logger.debug("No results found")
 
                         items[s] = testCases2BeDisplayed
-                except:
+                except Exception:
                     logger.error("Error: installer %s, version %s, scenario %s"
                                  % (installer, version, s))
                     logger.error("No data available: %s" % (sys.exc_info()[0]))
@@ -272,17 +276,18 @@ for version in versions:
             templateEnv = jinja2.Environment(
                 loader=templateLoader, autoescape=True)
 
-            TEMPLATE_FILE = "./functest/template/index-status-tmpl.html"
+            TEMPLATE_FILE = ("./reporting/functest/template"
+                             "/index-status-tmpl.html")
             template = templateEnv.get_template(TEMPLATE_FILE)
 
             outputText = template.render(
-                            scenario_stats=scenario_stats,
-                            scenario_results=scenario_result_criteria,
-                            items=items,
-                            installer=installer_display,
-                            period=period,
-                            version=version,
-                            date=reportingDate)
+                scenario_stats=scenario_stats,
+                scenario_results=scenario_result_criteria,
+                items=items,
+                installer=installer_display,
+                period=period,
+                version=version,
+                date=reportingDate)
 
             with open("./display/" + version +
                       "/functest/status-" +
@@ -295,8 +300,6 @@ for version in versions:
 
             # Generate outputs for export
             # pdf
-            # TODO Change once web site updated...use the current one
-            # to test pdf production
             url_pdf = rp_utils.get_config('general.url')
             pdf_path = ("./display/" + version +
                         "/functest/status-" + installer_display + ".html")
@@ -8,58 +8,57 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 # SPDX-license-identifier: Apache-2.0
 
-from urllib2 import Request, urlopen, URLError
 from datetime import datetime
 import json
-import jinja2
 import os
 
-# manage conf
-import utils.reporting_utils as rp_utils
+from urllib2 import Request, urlopen, URLError
+import jinja2
+
+import reporting.utils.reporting_utils as rp_utils
 
-installers = rp_utils.get_config('general.installers')
-items = ["tests", "Success rate", "duration"]
+INSTALLERS = rp_utils.get_config('general.installers')
+ITEMS = ["tests", "Success rate", "duration"]
 
 CURRENT_DIR = os.getcwd()
 
 PERIOD = rp_utils.get_config('general.period')
-criteria_nb_test = 165
-criteria_duration = 1800
-criteria_success_rate = 90
+CRITERIA_NB_TEST = 100
+CRITERIA_DURATION = 1800
+CRITERIA_SUCCESS_RATE = 100
 
 logger = rp_utils.getLogger("Tempest")
 logger.info("************************************************")
 logger.info("*   Generating reporting Tempest_smoke_serial  *")
-logger.info("*   Data retention = %s days                   *" % PERIOD)
+logger.info("*   Data retention = %s days                   *", PERIOD)
 logger.info("*                                              *")
 logger.info("************************************************")
 
 logger.info("Success criteria:")
-logger.info("nb tests executed > %s s " % criteria_nb_test)
-logger.info("test duration < %s s " % criteria_duration)
-logger.info("success rate > %s " % criteria_success_rate)
+logger.info("nb tests executed > %s s ", CRITERIA_NB_TEST)
+logger.info("test duration < %s s ", CRITERIA_DURATION)
+logger.info("success rate > %s ", CRITERIA_SUCCESS_RATE)
 
 # For all the versions
 for version in rp_utils.get_config('general.versions'):
-    for installer in installers:
+    for installer in INSTALLERS:
         # we consider the Tempest results of the last PERIOD days
         url = ("http://" + rp_utils.get_config('testapi.url') +
-               "?case=tempest_smoke_serial")
-        request = Request(url + '&period=' + str(PERIOD) +
-                          '&installer=' + installer +
-                          '&version=' + version)
-        logger.info("Search tempest_smoke_serial results for installer %s"
-                    " for version %s"
-                    % (installer, version))
+               "?case=tempest_smoke_serial&period=" + str(PERIOD) +
+               "&installer=" + installer + "&version=" + version)
+        request = Request(url)
+        logger.info(("Search tempest_smoke_serial results for installer %s"
+                     " for version %s"), installer, version)
         try:
             response = urlopen(request)
             k = response.read()
             results = json.loads(k)
-        except URLError as e:
-            logger.error("Error code: %s" % e)
-
+        except URLError as err:
+            logger.error("Error code: %s", err)
+        logger.debug("request sent: %s", url)
+        logger.debug("Results from API: %s", results)
         test_results = results['results']
-
+        logger.debug("Test results: %s", test_results)
         scenario_results = {}
         criteria = {}
         errors = {}
@@ -72,27 +71,37 @@ for version in rp_utils.get_config('general.versions'):
                 scenario_results[r['scenario']] = []
             scenario_results[r['scenario']].append(r)
 
+        logger.debug("Scenario results: %s", scenario_results)
+
         for s, s_result in scenario_results.items():
             scenario_results[s] = s_result[0:5]
             # For each scenario, we build a result object to deal with
             # results, criteria and error handling
             for result in scenario_results[s]:
                 result["start_date"] = result["start_date"].split(".")[0]
+                logger.debug("start_date= %s", result["start_date"])
 
                 # retrieve results
                 # ****************
                 nb_tests_run = result['details']['tests']
                 nb_tests_failed = result['details']['failures']
-                if nb_tests_run != 0:
-                    success_rate = 100 * ((int(nb_tests_run) -
+                logger.debug("nb_tests_run= %s", nb_tests_run)
+                logger.debug("nb_tests_failed= %s", nb_tests_failed)
+
+                try:
+                    success_rate = (100 * (int(nb_tests_run) -
                                            int(nb_tests_failed)) /
-                                          int(nb_tests_run))
-                else:
+                                    int(nb_tests_run))
+                except ZeroDivisionError:
                     success_rate = 0
 
                 result['details']["tests"] = nb_tests_run
                 result['details']["Success rate"] = str(success_rate) + "%"
 
+                logger.info("nb_tests_run= %s", result['details']["tests"])
+                logger.info("test rate = %s",
+                            result['details']["Success rate"])
+
                 # Criteria management
                 # *******************
                 crit_tests = False
@@ -100,11 +109,11 @@ for version in rp_utils.get_config('general.versions'):
                 crit_time = False
 
                 # Expect that at least 165 tests are run
-                if nb_tests_run >= criteria_nb_test:
+                if nb_tests_run >= CRITERIA_NB_TEST:
                     crit_tests = True
 
                 # Expect that at least 90% of success
-                if success_rate >= criteria_success_rate:
+                if success_rate >= CRITERIA_SUCCESS_RATE:
                     crit_rate = True
 
                 # Expect that the suite duration is inferior to 30m
@@ -114,39 +123,38 @@ for version in rp_utils.get_config('general.versions'):
                                                '%Y-%m-%d %H:%M:%S')
 
                 delta = stop_date - start_date
-                if (delta.total_seconds() < criteria_duration):
+
+                if delta.total_seconds() < CRITERIA_DURATION:
                     crit_time = True
 
                 result['criteria'] = {'tests': crit_tests,
                                       'Success rate': crit_rate,
                                       'duration': crit_time}
                 try:
-                    logger.debug("Scenario %s, Installer %s"
-                                 % (s_result[1]['scenario'], installer))
-                    logger.debug("Nb Test run: %s" % nb_tests_run)
-                    logger.debug("Test duration: %s"
-                                 % result['details']['duration'])
-                    logger.debug("Success rate: %s" % success_rate)
-                except:
+                    logger.debug("Nb Test run: %s", nb_tests_run)
+                    logger.debug("Test duration: %s", delta)
+                    logger.debug("Success rate: %s", success_rate)
+                except Exception:  # pylint: disable=broad-except
                     logger.error("Data format error")
 
                 # Error management
                 # ****************
                 try:
                     errors = result['details']['errors']
-                    result['errors'] = errors.replace('{0}', '')
-                except:
+                    logger.info("errors: %s", errors)
+                    result['errors'] = errors
+                except Exception:  # pylint: disable=broad-except
                     logger.error("Error field not present (Brahamputra runs?)")
 
         templateLoader = jinja2.FileSystemLoader(".")
         templateEnv = jinja2.Environment(loader=templateLoader,
                                          autoescape=True)
 
-        TEMPLATE_FILE = "./functest/template/index-tempest-tmpl.html"
+        TEMPLATE_FILE = "./reporting/functest/template/index-tempest-tmpl.html"
         template = templateEnv.get_template(TEMPLATE_FILE)
 
         outputText = template.render(scenario_results=scenario_results,
-                                     items=items,
+                                     items=ITEMS,
                                      installer=installer)
 
         with open("./display/" + version +
@@ -104,7 +104,7 @@ for version in versions:
                                  % result['details']['sig_test']['duration'])
                     logger.debug("Signaling testing results: %s"
                                  % format_result)
-                except:
+                except Exception:
                     logger.error("Data badly formatted")
                 logger.debug("----------------------------------------")
 
@@ -112,7 +112,7 @@ for version in versions:
         templateEnv = jinja2.Environment(loader=templateLoader,
                                          autoescape=True)
 
-        TEMPLATE_FILE = "./functest/template/index-vims-tmpl.html"
+        TEMPLATE_FILE = "./reporting/functest/template/index-vims-tmpl.html"
         template = templateEnv.get_template(TEMPLATE_FILE)
 
         outputText = template.render(scenario_results=scenario_results,
@@ -72,6 +72,7 @@ $(document).ready(function (){
             <li class="active"><a href="../../index.html">Home</a></li>
             <li><a href="status-apex.html">Apex</a></li>
             <li><a href="status-compass.html">Compass</a></li>
+            <li><a href="status-daisy.html">Daisy</a></li>
             <li><a href="status-fuel@x86.html">fuel@x86</a></li>
             <li><a href="status-fuel@aarch64.html">fuel@aarch64</a></li>
             <li><a href="status-joid.html">Joid</a></li>
@@ -89,7 +90,7 @@ $(document).ready(function (){
             <div class="panel-heading"><h4><b>List of last scenarios ({{version}}) run over the last {{period}} days </b></h4></div>
                 <table class="table">
                     <tr>
-                        <th width="40%">Scenario</th>
+                        <th width="40%">HA Scenario</th>
                         <th width="20%">Status</th>
                         <th width="20%">Trend</th>
                         <th width="10%">Score</th>
@@ -97,14 +98,39 @@ $(document).ready(function (){
                     </tr>
                         {% for scenario,iteration in scenario_stats.iteritems() -%}
                             <tr class="tr-ok">
+                            {% if '-ha' in scenario -%}
                                 <td><a href={{scenario_results[scenario].getUrlLastRun()}}>{{scenario}}</a></td>
                                 <td><div id="gaugeScenario{{loop.index}}"></div></td>
                                 <td><div id="trend_svg{{loop.index}}"></div></td>
                                 <td>{{scenario_results[scenario].getScore()}}</td>
                                 <td>{{iteration}}</td>
+                            {%- endif %}
+                            </tr>
+                            {%- endfor %}
+                            <br>
+                </table>
+                <br>
+               <table class="table">
+                    <tr>
+                        <th width="40%">NOHA Scenario</th>
+                        <th width="20%">Status</th>
+                        <th width="20%">Trend</th>
+                        <th width="10%">Score</th>
+                        <th width="10%">Iteration</th>
+                    </tr>
+                        {% for scenario,iteration in scenario_stats.iteritems() -%}
+                            <tr class="tr-ok">
+                            {% if '-noha' in scenario -%}
+                                <td><a href={{scenario_results[scenario].getUrlLastRun()}}>{{scenario}}</a></td>
+                                <td><div id="gaugeScenario{{loop.index}}"></div></td>
+                                <td><div id="trend_svg{{loop.index}}"></div></td>
+                                <td>{{scenario_results[scenario].getScore()}}</td>
+                                <td>{{iteration}}</td>
+                            {%- endif %}
                             </tr>
                             {%- endfor %}
-                        </table>
+                </table>
+
         </div>
 
 
@@ -23,7 +23,7 @@ reportingDate = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
 
 logger.info("*******************************************")
 logger.info("*   Generating reporting scenario status  *")
-logger.info("*   Data retention = %s days              *" % PERIOD)
+logger.info("*   Data retention = {} days              *".format(PERIOD))
 logger.info("*                                         *")
 logger.info("*******************************************")
 
@@ -33,7 +33,7 @@ def prepare_profile_file(version):
     if not os.path.exists(profile_dir):
         os.makedirs(profile_dir)
 
-    profile_file = '{}/scenario_history.txt'.format(profile_dir, version)
+    profile_file = "{}/scenario_history.txt".format(profile_dir)
     if not os.path.exists(profile_file):
         with open(profile_file, 'w') as f:
             info = 'date,scenario,installer,details,score\n'
@@ -77,7 +77,7 @@ def render_html(prof_results, installer, version):
     template_env = jinja2.Environment(loader=template_loader,
                                       autoescape=True)
 
-    template_file = "./qtip/template/index-status-tmpl.html"
+    template_file = "./reporting/qtip/template/index-status-tmpl.html"
     template = template_env.get_template(template_file)
 
     render_outcome = template.render(prof_results=prof_results,
@@ -106,5 +106,6 @@ def render_reporter():
         rp_utils.generate_csv(profile_file)
         logger.info("CSV generated...")
 
+
 if __name__ == '__main__':
     render_reporter()
         <nav>
           <ul class="nav nav-justified">
             <li class="active"><a href="http://testresults.opnfv.org/reporting/index.html">Home</a></li>
-            <li><a href="index-status-apex.html">Apex</a></li>
-            <li><a href="index-status-compass.html">Compass</a></li>
-            <li><a href="index-status-fuel.html">Fuel</a></li>
-            <li><a href="index-status-joid.html">Joid</a></li>
+            <li><a href="status-apex.html">Apex</a></li>
+            <li><a href="status-compass.html">Compass</a></li>
+            <li><a href="status-daisy.html">Daisy</a></li>
+            <li><a href="status-fuel.html">Fuel</a></li>
+            <li><a href="status-joid.html">Joid</a></li>
           </ul>
         </nav>
       </div>
similarity index 91%
rename from utils/test/reporting/reporting.yaml
rename to utils/test/reporting/reporting/reporting.yaml
index 1692f48..9bb90b8 100644 (file)
@@ -3,6 +3,7 @@ general:
     installers:
         - apex
         - compass
+        - daisy
         - fuel
         - joid
 
@@ -63,6 +64,10 @@ qtip:
     log_level: ERROR
     period: 1
 
-bottleneck:
+bottlenecks:
+    test_list:
+        - posca_factor_ping
+        - posca_factor_system_bandwidth
+    log_level: ERROR
 
 vsperf:
@@ -7,13 +7,12 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 #
 import datetime
-import jinja2
 import os
 
-# manage conf
-import utils.reporting_utils as rp_utils
+import jinja2
 
-import utils.scenarioResult as sr
+import reporting.utils.reporting_utils as rp_utils
+import reporting.utils.scenarioResult as sr
 
 installers = rp_utils.get_config('general.installers')
 versions = rp_utils.get_config('general.versions')
@@ -39,7 +38,8 @@ for version in versions:
     for installer in installers:
         # get scenarios results data
         # for the moment we consider only 1 case snia_steady_state
-        scenario_results = rp_utils.getScenarios("snia_steady_state",
+        scenario_results = rp_utils.getScenarios("storperf",
+                                                 "snia_steady_state",
                                                  installer,
                                                  version)
         # logger.info("scenario_results: %s" % scenario_results)
@@ -131,7 +131,7 @@ for version in versions:
         templateEnv = jinja2.Environment(loader=templateLoader,
                                          autoescape=True)
 
-        TEMPLATE_FILE = "./storperf/template/index-status-tmpl.html"
+        TEMPLATE_FILE = "./reporting/storperf/template/index-status-tmpl.html"
         template = templateEnv.get_template(TEMPLATE_FILE)
 
         outputText = template.render(scenario_results=scenario_result_criteria,
@@ -10,7 +10,7 @@
 import logging
 import unittest
 
-from utils import reporting_utils
+from reporting.utils import reporting_utils
 
 
 class reportingUtilsTesting(unittest.TestCase):
@@ -20,10 +20,9 @@ class reportingUtilsTesting(unittest.TestCase):
     def setUp(self):
         self.test = reporting_utils
 
-    def test_getConfig(self):
-        self.assertEqual(self.test.get_config("general.period"), 10)
-# TODO
-# ...
+    def test_foo(self):
+        self.assertTrue(0 < 1)
+
 
 if __name__ == "__main__":
     unittest.main(verbosity=2)
diff --git a/utils/test/reporting/reporting/utils/__init__.py b/utils/test/reporting/reporting/utils/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
@@ -20,15 +20,15 @@ import yaml
 #               YAML UTILS
 #
 # -----------------------------------------------------------
-def get_parameter_from_yaml(parameter, file):
+def get_parameter_from_yaml(parameter, config_file):
     """
     Returns the value of a given parameter in file.yaml
     parameter must be given in string format with dots
     Example: general.openstack.image_name
     """
-    with open(file) as f:
-        file_yaml = yaml.safe_load(f)
-    f.close()
+    with open(config_file) as my_file:
+        file_yaml = yaml.safe_load(my_file)
+    my_file.close()
     value = file_yaml
     for element in parameter.split("."):
         value = value.get(element)
@@ -39,6 +39,9 @@ def get_parameter_from_yaml(parameter, file):
 
 
 def get_config(parameter):
+    """
+    Get configuration parameter from yaml configuration file
+    """
     yaml_ = os.environ["CONFIG_REPORTING_YAML"]
     return get_parameter_from_yaml(parameter, yaml_)
 
@@ -49,20 +52,23 @@ def get_config(parameter):
 #
 # -----------------------------------------------------------
 def getLogger(module):
-    logFormatter = logging.Formatter("%(asctime)s [" +
-                                     module +
-                                     "] [%(levelname)-5.5s]  %(message)s")
+    """
+    Get Logger
+    """
+    log_formatter = logging.Formatter("%(asctime)s [" +
+                                      module +
+                                      "] [%(levelname)-5.5s]  %(message)s")
     logger = logging.getLogger()
     log_file = get_config('general.log.log_file')
     log_level = get_config('general.log.log_level')
 
-    fileHandler = logging.FileHandler("{0}/{1}".format('.', log_file))
-    fileHandler.setFormatter(logFormatter)
-    logger.addHandler(fileHandler)
+    file_handler = logging.FileHandler("{0}/{1}".format('.', log_file))
+    file_handler.setFormatter(log_formatter)
+    logger.addHandler(file_handler)
 
-    consoleHandler = logging.StreamHandler()
-    consoleHandler.setFormatter(logFormatter)
-    logger.addHandler(consoleHandler)
+    console_handler = logging.StreamHandler()
+    console_handler.setFormatter(log_formatter)
+    logger.addHandler(console_handler)
     logger.setLevel(log_level)
     return logger
 
@@ -73,6 +79,9 @@ def getLogger(module):
 #
 # -----------------------------------------------------------
 def getApiResults(case, installer, scenario, version):
+    """
+    Get Results by calling the API
+    """
     results = json.dumps([])
     # to remove proxy (to be removed at the end for local test only)
     # proxy_handler = urllib2.ProxyHandler({})
@@ -94,29 +103,32 @@ def getApiResults(case, installer, scenario, version):
         response = urlopen(request)
         k = response.read()
         results = json.loads(k)
-    except URLError as e:
-        print('No kittez. Got an error code:', e)
+    except URLError:
+        print "Error when retrieving results form API"
 
     return results
 
 
-def getScenarios(case, installer, version):
-
-    try:
-        case = case.getName()
-    except:
-        # if case is not an object test case, try the string
-        if type(case) == str:
-            case = case
-        else:
-            raise ValueError("Case cannot be evaluated")
+def getScenarios(project, case, installer, version):
+    """
+    Get the list of Scenarios
+    """
 
     period = get_config('general.period')
     url_base = get_config('testapi.url')
 
-    url = ("http://" + url_base + "?case=" + case +
-           "&period=" + str(period) + "&installer=" + installer +
-           "&version=" + version)
+    url = ("http://" + url_base +
+           "?installer=" + installer +
+           "&period=" + str(period))
+
+    if version is not None:
+        url += "&version=" + version
+
+    if project is not None:
+        url += "&project=" + project
+
+    if case is not None:
+        url += "&case=" + case
 
     try:
         request = Request(url)
@@ -124,50 +136,58 @@ def getScenarios(case, installer, version):
         k = response.read()
         results = json.loads(k)
         test_results = results['results']
-
-        page = results['pagination']['total_pages']
-        if page > 1:
-            test_results = []
-            for i in range(1, page + 1):
-                url_page = url + "&page=" + str(i)
-                request = Request(url_page)
-                response = urlopen(request)
-                k = response.read()
-                results = json.loads(k)
-                test_results += results['results']
+        try:
+            page = results['pagination']['total_pages']
+            if page > 1:
+                test_results = []
+                for i in range(1, page + 1):
+                    url_page = url + "&page=" + str(i)
+                    request = Request(url_page)
+                    response = urlopen(request)
+                    k = response.read()
+                    results = json.loads(k)
+                    test_results += results['results']
+        except KeyError:
+            print "No pagination detected"
     except URLError as err:
-        print('Got an error code:', err)
+        print 'Got an error code: {}'.format(err)
 
     if test_results is not None:
         test_results.reverse()
         scenario_results = {}
 
-        for r in test_results:
+        for my_result in test_results:
             # Retrieve all the scenarios per installer
-            if not r['scenario'] in scenario_results.keys():
-                scenario_results[r['scenario']] = []
+            if not my_result['scenario'] in scenario_results.keys():
+                scenario_results[my_result['scenario']] = []
             # Do we consider results from virtual pods ...
             # Do we consider results for non HA scenarios...
             exclude_virtual_pod = get_config('functest.exclude_virtual')
             exclude_noha = get_config('functest.exclude_noha')
-            if ((exclude_virtual_pod and "virtual" in r['pod_name']) or
-                    (exclude_noha and "noha" in r['scenario'])):
-                print("exclude virtual pod results...")
+            if ((exclude_virtual_pod and "virtual" in my_result['pod_name']) or
+                    (exclude_noha and "noha" in my_result['scenario'])):
+                print "exclude virtual pod results..."
             else:
-                scenario_results[r['scenario']].append(r)
+                scenario_results[my_result['scenario']].append(my_result)
 
     return scenario_results
 
 
 def getScenarioStats(scenario_results):
+    """
+    Get the number of occurence of scenarios over the defined PERIOD
+    """
     scenario_stats = {}
-    for k, v in scenario_results.iteritems():
-        scenario_stats[k] = len(v)
-
+    for res_k, res_v in scenario_results.iteritems():
+        scenario_stats[res_k] = len(res_v)
     return scenario_stats
 
 
 def getScenarioStatus(installer, version):
+    """
+    Get the status of a scenariofor Yardstick
+    they used criteria SUCCESS (default: PASS)
+    """
     period = get_config('general.period')
     url_base = get_config('testapi.url')
 
@@ -182,33 +202,37 @@ def getScenarioStatus(installer, version):
         response.close()
         results = json.loads(k)
         test_results = results['results']
-    except URLError as e:
-        print('Got an error code:', e)
+    except URLError:
+        print "GetScenarioStatus: error when calling the API"
 
     scenario_results = {}
     result_dict = {}
     if test_results is not None:
-        for r in test_results:
-            if r['stop_date'] != 'None' and r['criteria'] is not None:
-                if not r['scenario'] in scenario_results.keys():
-                    scenario_results[r['scenario']] = []
-                scenario_results[r['scenario']].append(r)
-
-        for k, v in scenario_results.items():
+        for test_r in test_results:
+            if (test_r['stop_date'] != 'None' and
+                    test_r['criteria'] is not None):
+                if not test_r['scenario'] in scenario_results.keys():
+                    scenario_results[test_r['scenario']] = []
+                scenario_results[test_r['scenario']].append(test_r)
+
+        for scen_k, scen_v in scenario_results.items():
             # scenario_results[k] = v[:LASTEST_TESTS]
             s_list = []
-            for element in v:
+            for element in scen_v:
                 if element['criteria'] == 'SUCCESS':
                     s_list.append(1)
                 else:
                     s_list.append(0)
-            result_dict[k] = s_list
+            result_dict[scen_k] = s_list
 
     # return scenario_results
     return result_dict
 
 
 def getQtipResults(version, installer):
+    """
+    Get QTIP results
+    """
     period = get_config('qtip.period')
     url_base = get_config('testapi.url')
 
@@ -223,7 +247,7 @@ def getQtipResults(version, installer):
         response.close()
         results = json.loads(k)['results']
     except URLError as err:
-        print('Got an error code:', err)
+        print 'Got an error code: {}'.format(err)
 
     result_dict = {}
     if results:
@@ -238,19 +262,24 @@ def getQtipResults(version, installer):
 
 
 def getNbtestOk(results):
+    """
+    based on default value (PASS) count the number of test OK
+    """
     nb_test_ok = 0
-    for r in results:
-        for k, v in r.iteritems():
+    for my_result in results:
+        for res_k, res_v in my_result.iteritems():
             try:
-                if "PASS" in v:
+                if "PASS" in res_v:
                     nb_test_ok += 1
-            except:
-                print("Cannot retrieve test status")
+            except Exception:
+                print "Cannot retrieve test status"
     return nb_test_ok
 
 
 def getResult(testCase, installer, scenario, version):
-
+    """
+    Get Result  for a given Functest Testcase
+    """
     # retrieve raw results
     results = getApiResults(testCase, installer, scenario, version)
     # let's concentrate on test results only
@@ -267,10 +296,10 @@ def getResult(testCase, installer, scenario, version):
         # print " ---------------- "
         # print "nb of results:" + str(len(test_results))
 
-        for r in test_results:
+        for res_r in test_results:
             # print r["start_date"]
             # print r["criteria"]
-            scenario_results.append({r["start_date"]: r["criteria"]})
+            scenario_results.append({res_r["start_date"]: res_r["criteria"]})
         # sort results
         scenario_results.sort()
         # 4 levels for the results
@@ -293,7 +322,7 @@ def getResult(testCase, installer, scenario, version):
             test_result_indicator = 1
         else:
             # Test the last 4 run
-            if (len(scenario_results) > 3):
+            if len(scenario_results) > 3:
                 last4runResults = scenario_results[-4:]
                 nbTestOkLast4 = getNbtestOk(last4runResults)
                 # print "Nb test OK (last 4 run):"+ str(nbTestOkLast4)
@@ -307,20 +336,23 @@ def getResult(testCase, installer, scenario, version):
 
 
 def getJenkinsUrl(build_tag):
-    # e.g. jenkins-functest-apex-apex-daily-colorado-daily-colorado-246
-    # id = 246
-    # jenkins-functest-compass-huawei-pod5-daily-master-136
-    # id = 136
-    # note it is linked to jenkins format
-    # if this format changes...function to be adapted....
+    """
+    Get Jenkins url_base corespoding to the last test CI run
+    e.g. jenkins-functest-apex-apex-daily-colorado-daily-colorado-246
+    id = 246
+    jenkins-functest-compass-huawei-pod5-daily-master-136
+    id = 136
+    note it is linked to jenkins format
+    if this format changes...function to be adapted....
+    """
     url_base = get_config('functest.jenkins_url')
     try:
         build_id = [int(s) for s in build_tag.split("-") if s.isdigit()]
         url_id = (build_tag[8:-(len(str(build_id[0])) + 1)] +
                   "/" + str(build_id[0]))
         jenkins_url = url_base + url_id + "/console"
-    except:
-        print('Impossible to get jenkins url:')
+    except Exception:
+        print 'Impossible to get jenkins url:'
 
     if "jenkins-" not in build_tag:
         jenkins_url = None
@@ -329,11 +361,14 @@ def getJenkinsUrl(build_tag):
 
 
 def getScenarioPercent(scenario_score, scenario_criteria):
+    """
+    Get success rate of the scenario (in %)
+    """
     score = 0.0
     try:
         score = float(scenario_score) / float(scenario_criteria) * 100
-    except:
-        print('Impossible to calculate the percentage score')
+    except Exception:
+        print 'Impossible to calculate the percentage score'
     return score
 
 
@@ -341,32 +376,41 @@ def getScenarioPercent(scenario_score, scenario_criteria):
 # Functest
 # *********
 def getFunctestConfig(version=""):
+    """
+    Get Functest configuration
+    """
     config_file = get_config('functest.test_conf') + version
     response = requests.get(config_file)
     return yaml.safe_load(response.text)
 
 
 def getArchitectures(scenario_results):
+    """
+    Get software architecture (x86 or Aarch64)
+    """
     supported_arch = ['x86']
-    if (len(scenario_results) > 0):
+    if len(scenario_results) > 0:
         for scenario_result in scenario_results.values():
             for value in scenario_result:
-                if ("armband" in value['build_tag']):
+                if "armband" in value['build_tag']:
                     supported_arch.append('aarch64')
                     return supported_arch
     return supported_arch
 
 
 def filterArchitecture(results, architecture):
+    """
+    Restrict the list of results based on given architecture
+    """
     filtered_results = {}
-    for name, results in results.items():
+    for name, res in results.items():
         filtered_values = []
-        for value in results:
-            if (architecture is "x86"):
+        for value in res:
+            if architecture is "x86":
                 # drop aarch64 results
                 if ("armband" not in value['build_tag']):
                     filtered_values.append(value)
-            elif(architecture is "aarch64"):
+            elif architecture is "aarch64":
                 # drop x86 results
                 if ("armband" in value['build_tag']):
                     filtered_values.append(value)
@@ -379,6 +423,9 @@ def filterArchitecture(results, architecture):
 # Yardstick
 # *********
 def subfind(given_list, pattern_list):
+    """
+    Yardstick util function
+    """
     LASTEST_TESTS = get_config('general.nb_iteration_tests_success_criteria')
     for i in range(len(given_list)):
         if given_list[i] == pattern_list[0] and \
@@ -388,7 +435,9 @@ def subfind(given_list, pattern_list):
 
 
 def _get_percent(status):
-
+    """
+    Yardstick util function to calculate success rate
+    """
     if status * 100 % 6:
         return round(float(status) * 100 / 6, 1)
     else:
@@ -396,13 +445,16 @@ def _get_percent(status):
 
 
 def get_percent(four_list, ten_list):
+    """
+    Yardstick util function to calculate success rate
+    """
     four_score = 0
     ten_score = 0
 
-    for v in four_list:
-        four_score += v
-    for v in ten_list:
-        ten_score += v
+    for res_v in four_list:
+        four_score += res_v
+    for res_v in ten_list:
+        ten_score += res_v
 
     LASTEST_TESTS = get_config('general.nb_iteration_tests_success_criteria')
     if four_score == LASTEST_TESTS:
@@ -418,9 +470,12 @@ def get_percent(four_list, ten_list):
 
 
 def _test():
+    """
+    Yardstick util function (test)
+    """
     status = getScenarioStatus("compass", "master")
-    print("status:++++++++++++++++++++++++")
-    print(json.dumps(status, indent=4))
+    print "status:++++++++++++++++++++++++"
+    print json.dumps(status, indent=4)
 
 
 # ----------------------------------------------------------
@@ -430,8 +485,9 @@ def _test():
 # -----------------------------------------------------------
 
 def export_csv(scenario_file_name, installer, version):
-    # csv
-    # generate sub files based on scenario_history.txt
+    """
+    Generate sub files based on scenario_history.txt
+    """
     scenario_installer_file_name = ("./display/" + version +
                                     "/functest/scenario_history_" +
                                     installer + ".csv")
@@ -441,21 +497,25 @@ def export_csv(scenario_file_name, installer, version):
         for line in scenario_file:
             if installer in line:
                 scenario_installer_file.write(line)
-        scenario_installer_file.close
+    scenario_installer_file.close
 
 
 def generate_csv(scenario_file):
+    """
+    Generate sub files based on scenario_history.txt
+    """
     import shutil
-    # csv
-    # generate sub files based on scenario_history.txt
     csv_file = scenario_file.replace('txt', 'csv')
     shutil.copy2(scenario_file, csv_file)
 
 
 def export_pdf(pdf_path, pdf_doc_name):
+    """
+    Export results to pdf
+    """
     try:
         pdfkit.from_file(pdf_path, pdf_doc_name)
     except IOError:
-        print("Error but pdf generated anyway...")
-    except:
-        print("impossible to generate PDF")
+        print "Error but pdf generated anyway..."
+    except Exception:
+        print "impossible to generate PDF"
diff --git a/utils/test/reporting/reporting/vsperf/__init__.py b/utils/test/reporting/reporting/vsperf/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/utils/test/reporting/reporting/vsperf/reporting-status.py b/utils/test/reporting/reporting/vsperf/reporting-status.py
new file mode 100644 (file)
index 0000000..fc4cc67
--- /dev/null
@@ -0,0 +1,138 @@
+#!/usr/bin/python
+#
+# This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+import datetime
+import os
+
+import jinja2
+
+import reporting.utils.reporting_utils as rp_utils
+import reporting.utils.scenarioResult as sr
+
+installers = rp_utils.get_config('general.installers')
+PERIOD = rp_utils.get_config('general.period')
+
+# Logger
+logger = rp_utils.getLogger("Storperf-Status")
+reportingDate = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
+
+logger.info("*******************************************")
+logger.info("*   Generating reporting scenario status  *")
+logger.info("*   Data retention = %s days              *" % PERIOD)
+logger.info("*                                         *")
+logger.info("*******************************************")
+
+# retrieve the list of storperf tests
+versions = {'master'}
+
+# For all the versions
+for version in versions:
+    # For all the installers
+    for installer in installers:
+        scenario_results = rp_utils.getScenarios("vsperf",
+                                                 None,
+                                                 installer,
+                                                 None)
+        items = {}
+        scenario_result_criteria = {}
+        logger.info("installer %s, version %s, scenario ", installer, version)
+
+        # From each scenarios get results list
+        for s, s_result in scenario_results.items():
+            logger.info("---------------------------------")
+            logger.info("installer %s, version %s, scenario %s", installer,
+                        version, s)
+            ten_criteria = len(s_result)
+
+            ten_score = 0
+            for v in s_result:
+                if "PASS" in v['criteria']:
+                    ten_score += 1
+
+            logger.info("ten_score: %s / %s" % (ten_score, ten_criteria))
+
+            four_score = 0
+            try:
+                LASTEST_TESTS = rp_utils.get_config(
+                    'general.nb_iteration_tests_success_criteria')
+                s_result.sort(key=lambda x: x['start_date'])
+                four_result = s_result[-LASTEST_TESTS:]
+                logger.debug("four_result: {}".format(four_result))
+                logger.debug("LASTEST_TESTS: {}".format(LASTEST_TESTS))
+                # logger.debug("four_result: {}".format(four_result))
+                four_criteria = len(four_result)
+                for v in four_result:
+                    if "PASS" in v['criteria']:
+                        four_score += 1
+                logger.info("4 Score: %s / %s " % (four_score,
+                                                   four_criteria))
+            except Exception:
+                logger.error("Impossible to retrieve the four_score")
+
+            try:
+                s_status = (four_score * 100) / four_criteria
+            except ZeroDivisionError:
+                s_status = 0
+            logger.info("Score percent = %s" % str(s_status))
+            s_four_score = str(four_score) + '/' + str(four_criteria)
+            s_ten_score = str(ten_score) + '/' + str(ten_criteria)
+            s_score_percent = str(s_status)
+
+            logger.debug(" s_status: {}".format(s_status))
+            if s_status == 100:
+                logger.info(">>>>> scenario OK, save the information")
+            else:
+                logger.info(">>>> scenario not OK, last 4 iterations = %s, \
+                             last 10 days = %s" % (s_four_score, s_ten_score))
+
+            s_url = ""
+            if len(s_result) > 0:
+                build_tag = s_result[len(s_result)-1]['build_tag']
+                logger.debug("Build tag: %s" % build_tag)
+                s_url = s_url = rp_utils.getJenkinsUrl(build_tag)
+                logger.info("last jenkins url: %s" % s_url)
+
+            # Save daily results in a file
+            path_validation_file = ("./display/" + version +
+                                    "/vsperf/scenario_history.txt")
+
+            if not os.path.exists(path_validation_file):
+                with open(path_validation_file, 'w') as f:
+                    info = 'date,scenario,installer,details,score\n'
+                    f.write(info)
+
+            with open(path_validation_file, "a") as f:
+                info = (reportingDate + "," + s + "," + installer +
+                        "," + s_ten_score + "," +
+                        str(s_score_percent) + "\n")
+                f.write(info)
+
+            scenario_result_criteria[s] = sr.ScenarioResult(s_status,
+                                                            s_four_score,
+                                                            s_ten_score,
+                                                            s_score_percent,
+                                                            s_url)
+
+            logger.info("--------------------------")
+
+        templateLoader = jinja2.FileSystemLoader(".")
+        templateEnv = jinja2.Environment(loader=templateLoader,
+                                         autoescape=True)
+
+        TEMPLATE_FILE = "./reporting/vsperf/template/index-status-tmpl.html"
+        template = templateEnv.get_template(TEMPLATE_FILE)
+
+        outputText = template.render(scenario_results=scenario_result_criteria,
+                                     installer=installer,
+                                     period=PERIOD,
+                                     version=version,
+                                     date=reportingDate)
+
+        with open("./display/" + version +
+                  "/vsperf/status-" + installer + ".html", "wb") as fh:
+            fh.write(outputText)
diff --git a/utils/test/reporting/reporting/vsperf/template/index-status-tmpl.html b/utils/test/reporting/reporting/vsperf/template/index-status-tmpl.html
new file mode 100644 (file)
index 0000000..7e06ef6
--- /dev/null
@@ -0,0 +1,114 @@
+ <html>
+  <head>
+    <meta charset="utf-8">
+    <!-- Bootstrap core CSS -->
+    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
+    <link href="../../css/default.css" rel="stylesheet">
+    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
+    <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script>
+    <script type="text/javascript" src="../../js/gauge.js"></script>
+    <script type="text/javascript" src="../../js/trend.js"></script>
+    <script>
+        function onDocumentReady() {
+            // Gauge management
+            {% for scenario in scenario_results.keys() -%}
+            var gaugeScenario{{loop.index}} = gauge('#gaugeScenario{{loop.index}}');
+            {%- endfor %}
+            // assign success rate to the gauge
+            function updateReadings() {
+                {% for scenario in scenario_results.keys() -%}
+                 gaugeScenario{{loop.index}}.update({{scenario_results[scenario].getScorePercent()}});
+                 {%- endfor %}
+            }
+            updateReadings();
+        }
+
+        // trend line management
+        d3.csv("./scenario_history.txt", function(data) {
+            // ***************************************
+            // Create the trend line
+            {% for scenario in scenario_results.keys() -%}
+            // for scenario {{scenario}}
+            // Filter results
+                var trend{{loop.index}} = data.filter(function(row) {
+                    return row["scenario"]=="{{scenario}}" && row["installer"]=="{{installer}}";
+                })
+            // Parse the date
+            trend{{loop.index}}.forEach(function(d) {
+                d.date = parseDate(d.date);
+                d.score = +d.score
+            });
+            // Draw the trend line
+            var mytrend = trend("#trend_svg{{loop.index}}",trend{{loop.index}})
+            // ****************************************
+            {%- endfor %}
+        });
+        if ( !window.isLoaded ) {
+            window.addEventListener("load", function() {
+            onDocumentReady();
+            }, false);
+        } else {
+            onDocumentReady();
+        }
+    </script>
+    <script type="text/javascript">
+    $(document).ready(function (){
+        $(".btn-more").click(function() {
+            $(this).hide();
+            $(this).parent().find(".panel-default").show();
+        });
+    })
+    </script>
+  </head>
+    <body>
+    <div class="container">
+      <div class="masthead">
+          <h3 class="text-muted">Vsperf status page ({{version}}, {{date}})</h3>
+        <nav>
+          <ul class="nav nav-justified">
+            <li class="active"><a href="http://testresults.opnfv.org/reporting/index.html">Home</a></li>
+            <li><a href="status-apex.html">Apex</a></li>
+            <li><a href="status-compass.html">Compass</a></li>
+            <li><a href="status-fuel.html">Fuel</a></li>
+            <li><a href="status-joid.html">Joid</a></li>
+          </ul>
+        </nav>
+      </div>
+<div class="row">
+    <div class="col-md-1"></div>
+    <div class="col-md-10">
+        <div class="page-header">
+            <h2>{{installer}}</h2>
+        </div>
+        <div><h1>Reported values represent the percentage of completed
+
+          CI tests during the reporting period, where results
+
+          were communicated to the Test Database.</h1></div>
+        <div class="scenario-overview">
+            <div class="panel-heading"><h4><b>List of last scenarios ({{version}}) run over the last {{period}} days </b></h4></div>
+                <table class="table">
+                    <tr>
+                        <th width="40%">Scenario</th>
+                        <th width="20%">Status</th>
+                        <th width="20%">Trend</th>
+                        <th width="10%">Last 4 Iterations</th>
+                        <th width="10%">Last 10 Days</th>
+                    </tr>
+                        {% for scenario,result in scenario_results.iteritems() -%}
+                            <tr class="tr-ok">
+                                <td><a href="{{scenario_results[scenario].getLastUrl()}}">{{scenario}}</a></td>
+                                <td><div id="gaugeScenario{{loop.index}}"></div></td>
+                                <td><div id="trend_svg{{loop.index}}"></div></td>
+                                <td>{{scenario_results[scenario].getFourDaysScore()}}</td>
+                                <td>{{scenario_results[scenario].getTenDaysScore()}}</td>
+                            </tr>
+                        {%- endfor %}
+                </table>
+        </div>
+
+
+    </div>
+    <div class="col-md-1"></div>
+</div>
diff --git a/utils/test/reporting/reporting/yardstick/__init__.py b/utils/test/reporting/reporting/yardstick/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
@@ -7,14 +7,13 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 #
 import datetime
-import jinja2
 import os
 
-import utils.scenarioResult as sr
-from scenarios import config as cf
+import jinja2
 
-# manage conf
-import utils.reporting_utils as rp_utils
+import reporting.utils.scenarioResult as sr
+import reporting.utils.reporting_utils as rp_utils
+from scenarios import config as cf
 
 installers = rp_utils.get_config('general.installers')
 versions = rp_utils.get_config('general.versions')
@@ -106,7 +105,7 @@ for version in versions:
         templateEnv = jinja2.Environment(loader=templateLoader,
                                          autoescape=True)
 
-        TEMPLATE_FILE = "./yardstick/template/index-status-tmpl.html"
+        TEMPLATE_FILE = "./reporting/yardstick/template/index-status-tmpl.html"
         template = templateEnv.get_template(TEMPLATE_FILE)
 
         outputText = template.render(scenario_results=scenario_result_criteria,
diff --git a/utils/test/reporting/requirements.txt b/utils/test/reporting/requirements.txt
new file mode 100644 (file)
index 0000000..344064d
--- /dev/null
@@ -0,0 +1,7 @@
+pdfkit>=0.6.1 # MIT
+wkhtmltopdf-pack>=0.12.3 # MIT
+PyYAML>=3.10.0 # MIT
+simplejson>=2.2.0 # MIT
+Jinja2!=2.9.0,!=2.9.1,!=2.9.2,!=2.9.3,!=2.9.4,>=2.8 # BSD License (3 clause)
+requests!=2.12.2,>=2.10.0 # Apache-2.0
+tornado>=4.4.2 # Apache-2.0
index 8c674ce..b83b550 100755 (executable)
@@ -1,44 +1,3 @@
 #!/bin/bash
-set -o errexit
-set -o pipefail
-
-
-# Get script directory
-SCRIPTDIR=`dirname $0`
-
-# Creating virtual environment
-if [ ! -z $VIRTUAL_ENV ]; then
-    venv=$VIRTUAL_ENV
-else
-    venv=$SCRIPTDIR/.venv
-    virtualenv $venv
-fi
-
-source $venv/bin/activate
-
-export CONFIG_REPORTING_YAML=$SCRIPTDIR/reporting.yaml
-
-# ***************
-# Run unit tests
-# ***************
-echo "Running unit tests..."
-
-# install python packages
-easy_install -U setuptools
-easy_install -U pip
-pip install -r $SCRIPTDIR/docker/requirements.pip
-pip install -e $SCRIPTDIR
-
-python $SCRIPTDIR/setup.py develop
-
-# unit tests
-# TODO: remove cover-erase
-# To be deleted when all functest packages will be listed
-nosetests --with-xunit \
-         --cover-package=$SCRIPTDIR/utils \
-         --with-coverage \
-         --cover-xml \
-         $SCRIPTDIR/tests/unit
-rc=$?
-
-deactivate
+tox
+exit $?
diff --git a/utils/test/reporting/setup.cfg b/utils/test/reporting/setup.cfg
new file mode 100644 (file)
index 0000000..9543945
--- /dev/null
@@ -0,0 +1,12 @@
+[metadata]
+name = reporting
+version = 1
+home-page = https://wiki.opnfv.org/display/testing
+
+[files]
+packages =
+    reporting
+    api
+scripts =
+    docker/reporting.sh
+    docker/web_server.sh
index 627785e..17849f6 100644 (file)
@@ -1,22 +1,23 @@
-##############################################################################
+#!/usr/bin/env python
+
+# Copyright (c) 2017 Orange and others.
+#
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Apache License, Version 2.0
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
 
-from setuptools import setup, find_packages
+# pylint: disable=missing-docstring
+import setuptools
 
+# In python < 2.7.4, a lazy loading of package `pbr` will break
+# setuptools if some other modules registered functions in `atexit`.
+# solution from: http://bugs.python.org/issue15881#msg170215
+try:
+    import multiprocessing  # noqa
+except ImportError:
+    pass
 
-setup(
-    name="reporting",
-    version="master",
-    packages=find_packages(),
-    include_package_data=True,
-    package_data={
-    },
-    url="https://www.opnfv.org",
-    install_requires=["coverage==4.1",
-                      "mock==1.3.0",
-                      "nose==1.3.7"],
-)
+setuptools.setup(
+    setup_requires=['pbr>=1.8'],
+    pbr=True)
diff --git a/utils/test/reporting/test-requirements.txt b/utils/test/reporting/test-requirements.txt
new file mode 100644 (file)
index 0000000..738f508
--- /dev/null
@@ -0,0 +1,5 @@
+coverage>=4.0 # Apache-2.0
+mock>=2.0 # BSD
+nose # LGPL
+flake8<2.6.0,>=2.5.4 # MIT
+pylint==1.4.5 # GPLv2
diff --git a/utils/test/reporting/tox.ini b/utils/test/reporting/tox.ini
new file mode 100644 (file)
index 0000000..2df5030
--- /dev/null
@@ -0,0 +1,27 @@
+[tox]
+envlist = pep8,pylint,py27
+
+[testenv]
+usedevelop = True
+deps =
+  -r{toxinidir}/requirements.txt
+  -r{toxinidir}/test-requirements.txt
+commands = nosetests --with-xunit \
+  --with-coverage \
+  --cover-tests \
+  --cover-package=reporting \
+  --cover-xml \
+  --cover-html \
+  reporting/tests/unit
+
+[testenv:pep8]
+basepython = python2.7
+commands = flake8
+
+[testenv:pylint]
+basepython = python2.7
+whitelist_externals = bash
+commands =
+  bash -c "\
+  pylint --disable=locally-disabled reporting| \
+    tee pylint.out | sed -ne '/Raw metrics/,//p'"
diff --git a/utils/test/testapi/.gitignore b/utils/test/testapi/.gitignore
new file mode 100644 (file)
index 0000000..86ec0d2
--- /dev/null
@@ -0,0 +1,7 @@
+AUTHORS
+ChangeLog
+setup.cfg-e
+opnfv_testapi/static
+build
+*.egg-info
+3rd_party/static/static
index 8c701c3..5f5b861 100644 (file)
         .module('testapiApp')
         .config(configureRoutes);
 
+    angular
+        .module('testapiApp')
+        .directive('dynamicModel', ['$compile', '$parse', function ($compile, $parse) {
+            return {
+                restrict: 'A',
+                terminal: true,
+                priority: 100000,
+                link: function (scope, elem) {
+                    var name = $parse(elem.attr('dynamic-model'))(scope);
+                    elem.removeAttr('dynamic-model');
+                    elem.attr('ng-model', name);
+                    $compile(elem)(scope);
+                }
+            };
+        }]);
+
     configureRoutes.$inject = ['$stateProvider', '$urlRouterProvider'];
 
     /**
                 url: '/about',
                 templateUrl: 'testapi-ui/components/about/about.html'
             }).
-            state('guidelines', {
-                url: '/guidelines',
-                templateUrl: 'testapi-ui/components/guidelines/guidelines.html',
-                controller: 'GuidelinesController as ctrl'
+            state('pods', {
+                url: '/pods',
+                templateUrl: 'testapi-ui/components/pods/pods.html',
+                controller: 'PodsController as ctrl'
             }).
             state('communityResults', {
                 url: '/community_results',
@@ -54,8 +70,8 @@
                 controller: 'ResultsController as ctrl'
             }).
             state('userResults', {
-                url: 'user_results',
-                templateUrl: '/testapi-ui/components/results/results.html',
+                url: '/user_results',
+                templateUrl: 'testapi-ui/components/results/results.html',
                 controller: 'ResultsController as ctrl'
             }).
             state('resultsDetail', {
@@ -66,7 +82,7 @@
             }).
             state('profile', {
                 url: '/profile',
-                templateUrl: '/testapi-ui/components/profile/profile.html',
+                templateUrl: 'testapi-ui/components/profile/profile.html',
                 controller: 'ProfileController as ctrl'
             }).
             state('authFailure', {
diff --git a/utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/guidelines.html b/utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/guidelines.html
deleted file mode 100644 (file)
index 1dd39ff..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<h3>OpenStack Powered&#8482; Guidelines</h3>
-
-<!-- Guideline Filters -->
-<div class="row">
-    <div class="col-md-3">
-        <strong>Version:</strong>
-        <!-- Slicing the version file name here gets rid of the '.json' file extension -->
-        <select ng-model="ctrl.version"
-                ng-change="ctrl.update()"
-                class="form-control"
-                ng-options="versionFile.slice(0,-5) for versionFile in ctrl.versionList">
-        </select>
-    </div>
-    <div class="col-md-4">
-        <strong>Target Program:</strong>
-        <span class="program-about"><a target="_blank" href="http://www.openstack.org/brand/interop/">About</a></span>
-        <select ng-model="ctrl.target" class="form-control" ng-change="ctrl.updateTargetCapabilities()">
-            <option value="platform">OpenStack Powered Platform</option>
-            <option value="compute">OpenStack Powered Compute</option>
-            <option value="object">OpenStack Powered Object Storage</option>
-        </select>
-    </div>
-</div>
-
-<br />
-<div ng-if="ctrl.guidelines">
-    <strong>Guideline Status:</strong>
-    {{ctrl.guidelines.status | capitalize}}
-</div>
-
-<div ng-show="ctrl.guidelines">
-    <strong>Corresponding OpenStack Releases:</strong>
-    <ul class="list-inline">
-        <li ng-repeat="release in ctrl.guidelines.releases">
-            {{release | capitalize}}
-        </li>
-    </ul>
-</div>
-
-<strong>Capability Status:</strong>
-<div class="checkbox">
-    <label>
-    <input type="checkbox" ng-model="ctrl.status.required">
-    <span class="required">Required</span>
-    </label>
-    <label>
-    <input type="checkbox" ng-model="ctrl.status.advisory">
-    <span class="advisory">Advisory</span>
-    </label>
-    <label>
-    <input type="checkbox" ng-model="ctrl.status.deprecated">
-    <span class="deprecated">Deprecated</span>
-    </label>
-    <label>
-    <input type="checkbox" ng-model="ctrl.status.removed">
-    <span class="removed">Removed</span>
-    </label>
-    <a class="test-list-dl pull-right"
-       title="Get a test list for capabilities matching selected statuses."
-       ng-click="ctrl.openTestListModal()">
-
-        Test List <span class="glyphicon glyphicon-file"></span>
-    </a>
-</div>
-<!-- End Capability Filters -->
-
-<p><small>Tests marked with <span class="glyphicon glyphicon-flag text-warning"></span> are tests flagged by Interop Working Group.</small></p>
-
-<!-- Loading animation divs -->
-<div cg-busy="{promise:ctrl.versionsRequest,message:'Loading versions'}"></div>
-<div cg-busy="{promise:ctrl.capsRequest,message:'Loading capabilities'}"></div>
-
-<!-- Get the version-specific template -->
-<div ng-include src="ctrl.detailsTemplate"></div>
-
-<div ng-show="ctrl.showError" class="alert alert-danger" role="alert">
-    <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
-    <span class="sr-only">Error:</span>
-    {{ctrl.error}}
-</div>
diff --git a/utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/guidelinesController.js b/utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/guidelinesController.js
deleted file mode 100644 (file)
index a6f4258..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-(function () {
-    'use strict';
-
-    angular
-        .module('testapiApp')
-        .controller('GuidelinesController', GuidelinesController);
-
-    GuidelinesController.$inject = ['$http', '$uibModal', 'testapiApiUrl'];
-
-    /**
-     * TestAPI Guidelines Controller
-     * This controller is for the '/guidelines' page where a user can browse
-     * through tests belonging to Interop WG defined capabilities.
-     */
-    function GuidelinesController($http, $uibModal, testapiApiUrl) {
-        var ctrl = this;
-
-        ctrl.getVersionList = getVersionList;
-        ctrl.update = update;
-        ctrl.updateTargetCapabilities = updateTargetCapabilities;
-        ctrl.filterStatus = filterStatus;
-        ctrl.getObjectLength = getObjectLength;
-        ctrl.openTestListModal = openTestListModal;
-
-        /** The target OpenStack marketing program to show capabilities for. */
-        ctrl.target = 'platform';
-
-        /** The various possible capability statuses. */
-        ctrl.status = {
-            required: true,
-            advisory: false,
-            deprecated: false,
-            removed: false
-        };
-
-        /**
-         * The template to load for displaying capability details.
-         */
-        ctrl.detailsTemplate = 'components/guidelines/partials/' +
-                               'guidelineDetails.html';
-
-        /**
-         * Retrieve an array of available guideline files from the TestAPI
-         * API server, sort this array reverse-alphabetically, and store it in
-         * a scoped variable. The scope's selected version is initialized to
-         * the latest (i.e. first) version here as well. After a successful API
-         * call, the function to update the capabilities is called.
-         * Sample API return array: ["2015.03.json", "2015.04.json"]
-         */
-        function getVersionList() {
-            var content_url = testapiApiUrl + '/guidelines';
-            ctrl.versionsRequest =
-                $http.get(content_url).success(function (data) {
-                    ctrl.versionList = data.sort().reverse();
-                    // Default to the first approved guideline which is expected
-                    // to be at index 1.
-                    ctrl.version = ctrl.versionList[1];
-                    ctrl.update();
-                }).error(function (error) {
-                    ctrl.showError = true;
-                    ctrl.error = 'Error retrieving version list: ' +
-                        angular.toJson(error);
-                });
-        }
-
-        /**
-         * This will contact the TestAPI API server to retrieve the JSON
-         * content of the guideline file corresponding to the selected
-         * version.
-         */
-        function update() {
-            var content_url = testapiApiUrl + '/guidelines/' + ctrl.version;
-            ctrl.capsRequest =
-                $http.get(content_url).success(function (data) {
-                    ctrl.guidelines = data;
-                    ctrl.updateTargetCapabilities();
-                }).error(function (error) {
-                    ctrl.showError = true;
-                    ctrl.guidelines = null;
-                    ctrl.error = 'Error retrieving guideline content: ' +
-                        angular.toJson(error);
-                });
-        }
-
-        /**
-         * This will update the scope's 'targetCapabilities' object with
-         * capabilities belonging to the selected OpenStack marketing program
-         * (programs typically correspond to 'components' in the Interop WG
-         * schema). Each capability will have its status mapped to it.
-         */
-        function updateTargetCapabilities() {
-            ctrl.targetCapabilities = {};
-            var components = ctrl.guidelines.components;
-            var targetCaps = ctrl.targetCapabilities;
-
-            // The 'platform' target is comprised of multiple components, so
-            // we need to get the capabilities belonging to each of its
-            // components.
-            if (ctrl.target === 'platform') {
-                var platform_components = ctrl.guidelines.platform.required;
-
-                // This will contain status priority values, where lower
-                // values mean higher priorities.
-                var statusMap = {
-                    required: 1,
-                    advisory: 2,
-                    deprecated: 3,
-                    removed: 4
-                };
-
-                // For each component required for the platform program.
-                angular.forEach(platform_components, function (component) {
-                    // Get each capability list belonging to each status.
-                    angular.forEach(components[component],
-                        function (caps, status) {
-                            // For each capability.
-                            angular.forEach(caps, function(cap) {
-                                // If the capability has already been added.
-                                if (cap in targetCaps) {
-                                    // If the status priority value is less
-                                    // than the saved priority value, update
-                                    // the value.
-                                    if (statusMap[status] <
-                                        statusMap[targetCaps[cap]]) {
-                                        targetCaps[cap] = status;
-                                    }
-                                }
-                                else {
-                                    targetCaps[cap] = status;
-                                }
-                            });
-                        });
-                });
-            }
-            else {
-                angular.forEach(components[ctrl.target],
-                    function (caps, status) {
-                        angular.forEach(caps, function(cap) {
-                            targetCaps[cap] = status;
-                        });
-                    });
-            }
-        }
-
-        /**
-         * This filter will check if a capability's status corresponds
-         * to a status that is checked/selected in the UI. This filter
-         * is meant to be used with the ng-repeat directive.
-         * @param {Object} capability
-         * @returns {Boolean} True if capability's status is selected
-         */
-        function filterStatus(capability) {
-            var caps = ctrl.targetCapabilities;
-            return (ctrl.status.required &&
-                caps[capability.id] === 'required') ||
-                (ctrl.status.advisory &&
-                caps[capability.id] === 'advisory') ||
-                (ctrl.status.deprecated &&
-                caps[capability.id] === 'deprecated') ||
-                (ctrl.status.removed &&
-                caps[capability.id] === 'removed');
-        }
-
-        /**
-         * This function will get the length of an Object/dict based on
-         * the number of keys it has.
-         * @param {Object} object
-         * @returns {Number} length of object
-         */
-        function getObjectLength(object) {
-            return Object.keys(object).length;
-        }
-
-        /**
-         * This will open the modal that will show a list of all tests
-         * belonging to capabilities with the selected status(es).
-         */
-        function openTestListModal() {
-            $uibModal.open({
-                templateUrl: '/components/guidelines/partials' +
-                        '/testListModal.html',
-                backdrop: true,
-                windowClass: 'modal',
-                animation: true,
-                controller: 'TestListModalController as modal',
-                size: 'lg',
-                resolve: {
-                    version: function () {
-                        return ctrl.version.slice(0, -5);
-                    },
-                    target: function () {
-                        return ctrl.target;
-                    },
-                    status: function () {
-                        return ctrl.status;
-                    }
-                }
-            });
-        }
-
-        ctrl.getVersionList();
-    }
-
-    angular
-        .module('testapiApp')
-        .controller('TestListModalController', TestListModalController);
-
-    TestListModalController.$inject = [
-        '$uibModalInstance', '$http', 'version',
-        'target', 'status', 'testapiApiUrl'
-    ];
-
-    /**
-     * Test List Modal Controller
-     * This controller is for the modal that appears if a user wants to see the
-     * test list corresponding to Interop WG capabilities with the selected
-     * statuses.
-     */
-    function TestListModalController($uibModalInstance, $http, version,
-        target, status, testapiApiUrl) {
-
-        var ctrl = this;
-
-        ctrl.version = version;
-        ctrl.target = target;
-        ctrl.status = status;
-        ctrl.close = close;
-        ctrl.updateTestListString = updateTestListString;
-
-        ctrl.aliases = true;
-        ctrl.flagged = false;
-
-        // Check if the API URL is absolute or relative.
-        if (testapiApiUrl.indexOf('http') > -1) {
-            ctrl.url = testapiApiUrl;
-        }
-        else {
-            ctrl.url = location.protocol + '//' + location.host +
-                testapiApiUrl;
-        }
-
-        /**
-         * This function will close/dismiss the modal.
-         */
-        function close() {
-            $uibModalInstance.dismiss('exit');
-        }
-
-        /**
-         * This function will return a list of statuses based on which ones
-         * are selected.
-         */
-        function getStatusList() {
-            var statusList = [];
-            angular.forEach(ctrl.status, function(value, key) {
-                if (value) {
-                    statusList.push(key);
-                }
-            });
-            return statusList;
-        }
-
-        /**
-         * This will get the list of tests from the API and update the
-         * controller's test list string variable.
-         */
-        function updateTestListString() {
-            var statuses = getStatusList();
-            if (!statuses.length) {
-                ctrl.error = 'No tests matching selected criteria.';
-                return;
-            }
-            ctrl.testListUrl = [
-                ctrl.url, '/guidelines/', ctrl.version, '/tests?',
-                'target=', ctrl.target, '&',
-                'type=', statuses.join(','), '&',
-                'alias=', ctrl.aliases.toString(), '&',
-                'flag=', ctrl.flagged.toString()
-            ].join('');
-            ctrl.testListRequest =
-                $http.get(ctrl.testListUrl).
-                    then(function successCallback(response) {
-                        ctrl.error = null;
-                        ctrl.testListString = response.data;
-                        if (!ctrl.testListString) {
-                            ctrl.testListCount = 0;
-                        }
-                        else {
-                            ctrl.testListCount =
-                                ctrl.testListString.split('\n').length;
-                        }
-                    }, function errorCallback(response) {
-                        ctrl.testListString = null;
-                        ctrl.testListCount = null;
-                        if (angular.isObject(response.data) &&
-                            response.data.message) {
-                            ctrl.error = 'Error retrieving test list: ' +
-                                response.data.message;
-                        }
-                        else {
-                            ctrl.error = 'Unknown error retrieving test list.';
-                        }
-                    });
-        }
-
-        updateTestListString();
-    }
-})();
diff --git a/utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/partials/guidelineDetails.html b/utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/partials/guidelineDetails.html
deleted file mode 100644 (file)
index f020c9a..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<!--
-HTML for guidelines page for all OpenStack Powered (TM) guideline schemas
-This expects the JSON data of the guidelines file to be stored in scope
-variable 'guidelines'.
--->
-
-<ol ng-show="ctrl.guidelines" class="capabilities">
-  <li class="capability-list-item" ng-repeat="capability in ctrl.guidelines.capabilities | arrayConverter | filter:ctrl.filterStatus | orderBy:'id'">
-    <span class="capability-name">{{capability.id}}</span><br />
-    <em>{{capability.description}}</em><br />
-    Status: <span class="{{ctrl.targetCapabilities[capability.id]}}">{{ctrl.targetCapabilities[capability.id]}}</span><br />
-    <span ng-if="capability.project">Project: {{capability.project | capitalize}}<br /></span>
-    <a ng-click="showAchievements = !showAchievements">Achievements ({{capability.achievements.length}})</a><br />
-    <ol uib-collapse="!showAchievements" class="list-inline">
-        <li ng-repeat="achievement in capability.achievements">
-            {{achievement}}
-        </li>
-    </ol>
-
-    <a ng-click="showTests = !showTests">Tests ({{ctrl.getObjectLength(capability.tests)}})</a>
-    <ul uib-collapse="!showTests">
-        <li ng-if="ctrl.guidelines.schema === '1.2'" ng-repeat="test in capability.tests">
-           <span ng-class="{'glyphicon glyphicon-flag text-warning': capability.flagged.indexOf(test) > -1}"></span>
-           {{test}}
-        </li>
-        <li ng-if="ctrl.guidelines.schema > '1.2'" ng-repeat="(testName, testDetails) in capability.tests">
-           <span ng-class="{'glyphicon glyphicon-flag text-warning': testDetails.flagged}" title="{{testDetails.flagged.reason}}"></span>
-           {{testName}}
-           <div class="test-detail" ng-if="testDetails.aliases">
-               <strong>Aliases:</strong>
-               <ul><li ng-repeat="alias in testDetails.aliases">{{alias}}</li></ul>
-           </div>
-        </li>
-    </ul>
-  </li>
-</ol>
-
-<div ng-show="ctrl.guidelines" class="criteria">
-    <hr>
-    <h4><a ng-click="showCriteria = !showCriteria">Criteria</a></h4>
-    <div uib-collapse="showCriteria">
-        <ul>
-            <li ng-repeat="(key, criterion) in ctrl.guidelines.criteria">
-                <span class="criterion-name">{{criterion.name}}</span><br />
-                <em>{{criterion.Description}}</em><br />
-                Weight: {{criterion.weight}}
-            </li>
-        </ul>
-    </div>
-</div>
diff --git a/utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/partials/testListModal.html b/utils/test/testapi/3rd_party/static/testapi-ui/components/guidelines/partials/testListModal.html
deleted file mode 100644 (file)
index 5b1d698..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<div class="modal-content">
-    <div class="modal-header">
-        <button type="button" class="close" aria-hidden="true" ng-click="modal.close()">&times;</button>
-        <h4>Test List ({{modal.testListCount}})</h4>
-        <p>Use this test list with <a title="testapi-client" target="_blank"href="https://github.com/openstack/testapi-client">testapi-client</a>
-           to run only tests in the {{modal.version}} OpenStack Powered&#8482; guideline from capabilities with the following statuses:
-        </p>
-        <ul class="list-inline">
-            <li class="required" ng-if="modal.status.required"> Required</li>
-            <li class="advisory" ng-if="modal.status.advisory"> Advisory</li>
-            <li class="deprecated" ng-if="modal.status.deprecated"> Deprecated</li>
-            <li class="removed" ng-if="modal.status.removed"> Removed</li>
-        </ul>
-        <div class="checkbox checkbox-test-list">
-            <label><input type="checkbox" ng-model="modal.aliases" ng-change="modal.updateTestListString()">Aliases</label>
-            <span class="glyphicon glyphicon-info-sign info-hover" aria-hidden="true"
-                  title="Include test aliases as tests may have been renamed over time. It does not hurt to include these."></span>
-            &nbsp;
-            <label><input type="checkbox" ng-model="modal.flagged" ng-change="modal.updateTestListString()">Flagged</label>
-            <span class="glyphicon glyphicon-info-sign info-hover" aria-hidden="true"
-                  title="Include flagged tests.">
-            </span>
-        </div>
-        <p ng-hide="modal.error"> Alternatively, get the test list directly from the API on your CLI:</p>
-        <code ng-hide="modal.error">wget "{{modal.testListUrl}}" -O {{modal.version}}-test-list.txt</code>
-    </div>
-    <div class="modal-body tests-modal-content">
-        <div cg-busy="{promise:modal.testListRequest,message:'Loading'}"></div>
-        <div ng-show="modal.error" class="alert alert-danger" role="alert">
-            <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
-            <span class="sr-only">Error:</span>
-            {{modal.error}}
-        </div>
-        <div class="form-group">
-            <textarea class="form-control" rows="16" id="tests" wrap="off">{{modal.testListString}}</textarea>
-        </div>
-    </div>
-    <div class="modal-footer">
-        <a target="_blank" href="{{modal.testListUrl}}" download="{{modal.version + '-test-list.txt'}}">
-            <button class="btn btn-primary" ng-if="modal.testListCount > 0" type="button">
-                Download
-            </button>
-        </a>
-        <button class="btn btn-primary" type="button" ng-click="modal.close()">Close</button>
-    </div>
-</div>
diff --git a/utils/test/testapi/3rd_party/static/testapi-ui/components/pods/pods.html b/utils/test/testapi/3rd_party/static/testapi-ui/components/pods/pods.html
new file mode 100644 (file)
index 0000000..e366670
--- /dev/null
@@ -0,0 +1,75 @@
+<h3>Pods</h3>
+<p>This page is used to create or query pods.<br>
+    Querying pods is open to everybody.<br>
+    But only login users are granted the privilege to create the new pod.
+</p>
+
+<div class="row" style="margin-bottom:24px;"></div>
+
+<div class="pod-create" ng-class="{ 'hidden': ! auth.isAuthenticated }">
+    <h4>Create</h4>
+    <div class="row">
+        <div ng-repeat="require in ctrl.createRequirements">
+            <div class="create-pod" style="margin-left:24px;">
+                <p class="input-group">
+                    <label for="cpid">{{require.label|capitalize}}: </label>
+                    <a ng-if="require.type == 'select'">
+                        <select dynamic-model="'ctrl.' + require.label" ng-options="option for option in require.selects"></select>
+                    </a>
+                    <a ng-if="require.type == 'text'">
+                        <input type="text" dynamic-model="'ctrl.' + require.label"/>
+                    </a>
+                    <a ng-if="require.type == 'textarea'">
+                        <textarea rows="2" cols="50" dynamic-model="'ctrl.' + require.label">
+                        </textarea>
+                    </a>
+                </p>
+            </div>
+        </div>
+
+        <div class="col-md-3" style="margin-top:12px; margin-left:8px;">
+            <button type="submit" class="btn btn-primary" ng-click="ctrl.create()">Create</button>
+        </div>
+    </div>
+</div>
+
+<div class="pods-filters" style="margin-top:36px;">
+    <h4>Filters</h4>
+    <div class="row">
+        <div class="col-md-3" style="margin-top:12px; margin-left:8px;">
+            <button type="submit" class="btn btn-primary" ng-click="ctrl.update()">Filter</button>
+            <button type="submit" class="btn btn-primary btn-danger" ng-click="ctrl.clearFilters()">Clear</button>
+        </div>
+    </div>
+</div>
+
+<div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div>
+<div cg-busy="{promise:ctrl.podsRequest,message:'Loading'}"></div>
+
+<div ng-show="ctrl.data" class="pods-table" style="margin-top:24px; margin-left:8px;">
+    <table ng-data="ctrl.data.pods" ng-show="ctrl.data" class="table table-striped table-hover">
+        <tbody>
+            <tr ng-repeat-start="(index, pod) in ctrl.data.pods">
+                <td>
+                    <a href="#" ng-click="showPod = !showPod">{{pod.name}}</a>
+                    <div class="show-pod" ng-class="{ 'hidden': ! showPod }" style="margin-left:24px;">
+                        <p>
+                            role: {{pod.role}}<br>
+                            mode: {{pod.mode}}<br>
+                            create_date: {{pod.creation_date}}<br>
+                            details: {{pod.details}}
+                        </p>
+                    </div>
+                </td>
+            </tr>
+            <tr ng-repeat-end=>
+            </tr>
+        </tbody>
+    </table>
+</div>
+<br>
+<div ng-show="ctrl.showError" class="alert alert-danger" role="alert">
+    <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
+    <span class="sr-only">Error:</span>
+    {{ctrl.error}}
+</div>
diff --git a/utils/test/testapi/3rd_party/static/testapi-ui/components/pods/podsController.js b/utils/test/testapi/3rd_party/static/testapi-ui/components/pods/podsController.js
new file mode 100644 (file)
index 0000000..894fcc1
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function () {
+    'use strict';
+
+    angular
+        .module('testapiApp')
+        .controller('PodsController', PodsController);
+
+    PodsController.$inject = [
+        '$rootScope', '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert'
+    ];
+
+    /**
+     * TestAPI Pods Controller
+     * This controller is for the '/pods' page where a user can browse
+     * through pods declared in TestAPI.
+     */
+    function PodsController($scope, $http, $filter, $state, testapiApiUrl,
+        raiseAlert) {
+        var ctrl = this;
+        ctrl.url = testapiApiUrl + '/pods';
+
+        ctrl.create = create;
+        ctrl.update = update;
+        ctrl.open = open;
+        ctrl.clearFilters = clearFilters;
+
+        ctrl.roles = ['community-ci', 'production-ci'];
+        ctrl.modes = ['metal', 'virtual'];
+        ctrl.createRequirements = [
+            {label: 'name', type: 'text', required: true},
+            {label: 'mode', type: 'select', selects: ctrl.modes},
+            {label: 'role', type: 'select', selects: ctrl.roles},
+            {label: 'details', type: 'textarea', required: false}
+        ];
+
+        ctrl.name = '';
+        ctrl.role = 'community-ci';
+        ctrl.mode = 'metal';
+        ctrl.details = '';
+
+        /**
+         * This is called when the date filter calendar is opened. It
+         * does some event handling, and sets a scope variable so the UI
+         * knows which calendar was opened.
+         * @param {Object} $event - The Event object
+         * @param {String} openVar - Tells which calendar was opened
+         */
+        function open($event, openVar) {
+            $event.preventDefault();
+            $event.stopPropagation();
+            ctrl[openVar] = true;
+        }
+
+        /**
+         * This function will clear all filters and update the results
+         * listing.
+         */
+        function clearFilters() {
+            ctrl.update();
+        }
+
+        /**
+         * This will contact the TestAPI to create a new pod.
+         */
+        function create() {
+            ctrl.showError = false;
+
+            if(ctrl.name != ""){
+                var pods_url = ctrl.url;
+                var body = {
+                    name: ctrl.name,
+                    mode: ctrl.mode,
+                    role: ctrl.role,
+                    details: ctrl.details
+                };
+                ctrl.podsRequest =
+                    $http.post(pods_url, body).error(function (error) {
+                        ctrl.showError = true;
+                        ctrl.error =
+                            'Error creating the new pod from server: ' +
+                            angular.toJson(error);
+                    });
+            }
+            else{
+                ctrl.showError = true;
+                        ctrl.error = 'Name is missing.'
+            }
+        }
+
+        /**
+         * This will contact the TestAPI to get a listing of declared pods.
+         */
+        function update() {
+            ctrl.showError = false;
+            ctrl.podsRequest =
+                $http.get(ctrl.url).success(function (data) {
+                    ctrl.data = data;
+                }).error(function (error) {
+                    ctrl.data = null;
+                    ctrl.showError = true;
+                    ctrl.error =
+                        'Error retrieving pods from server: ' +
+                        angular.toJson(error);
+                });
+        }
+    }
+})();
index dc97c41..763f5d1 100644 (file)
@@ -3,9 +3,16 @@
 <div>
     <table class="table table-striped table-hover">
         <tbody>
-            <tr> <td>User name</td> <td>{{auth.currentUser.fullname}}</td> </tr>
-            <tr> <td>User OpenId</td> <td>{{auth.currentUser.openid}}</td> </tr>
+            <tr> <td>User</td> <td>{{auth.currentUser.user}}</td> </tr>
+            <tr> <td>Fullname</td> <td>{{auth.currentUser.fullname}}</td> </tr>
             <tr> <td>Email</td> <td>{{auth.currentUser.email}}</td> </tr>
+            <tr> <td>Groups</td>
+                 <td>
+                     <div ng-repeat="group in auth.currentUser.groups">
+                         {{group}}</br>
+                     </div>
+                 </td>
+            </tr>
         </tbody>
     </table>
 </div>
index 0660e19..5dbdf7b 100644 (file)
@@ -26,7 +26,7 @@
      * This is a provider for the user's uploaded public keys.
      */
     function PubKeys($resource, testapiApiUrl) {
-        return $resource(testapiApiUrl + '/profile/pubkeys/:id', null, null);
+        return $resource(testapiApiUrl + '/user/pubkeys/:id', null, null);
     }
 
     angular
index 3056e1d..2ae5339 100644 (file)
@@ -1,6 +1,23 @@
 <h3>{{ctrl.pageHeader}}</h3>
 <p>{{ctrl.pageParagraph}}</p>
-
+<form class="form-inline" ng-show="ctrl.isUserResults">
+<h4>Upload Results</h4>
+<div class="form-group col-m-3">
+     <input class="form-contrl btn btn-default" type = "file" file-model = "resultFile"/>
+</div>
+<div class="checkbox col-m-1">
+  <label>
+      <input type="checkbox" ng-model="ctrl.isPublic">public
+  </label>
+</div>
+<div class="form-group col-m-3">
+     <button class="btn btn-primary" ng-click = "ctrl.uploadFile()">upload result</button>
+</div>
+<div>
+<lable>{{ctrl.uploadState}}</label>
+</div>
+</form>
+<div class="row" style="margin-bottom:24px;"></div>
 <div class="result-filters">
     <h4>Filters</h4>
     <div class="row">
@@ -41,7 +58,6 @@
 
 <div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div>
 <div cg-busy="{promise:ctrl.resultsRequest,message:'Loading'}"></div>
-
 <div ng-show="ctrl.data" class="results-table">
     <table ng-data="ctrl.data.result" ng-show="ctrl.data" class="table table-striped table-hover">
         <thead>
index 9e3540d..cc6cc0b 100644 (file)
         .module('testapiApp')
         .controller('ResultsController', ResultsController);
 
+    angular
+        .module('testapiApp')
+        .directive('fileModel', ['$parse', function ($parse) {
+            return {
+               restrict: 'A',
+               link: function(scope, element, attrs) {
+                  var model = $parse(attrs.fileModel);
+                  var modelSetter = model.assign;
+
+                  element.bind('change', function(){
+                     scope.$apply(function(){
+                        modelSetter(scope, element[0].files[0]);
+                     });
+                  });
+               }
+            };
+         }]);
+
     ResultsController.$inject = [
         '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert'
     ];
@@ -32,6 +50,7 @@
         raiseAlert) {
         var ctrl = this;
 
+        ctrl.uploadFile=uploadFile;
         ctrl.update = update;
         ctrl.open = open;
         ctrl.clearFilters = clearFilters;
@@ -76,6 +95,8 @@
         ctrl.format = 'yyyy-MM-dd';
 
         /** Check to see if this page should display user-specific results. */
+        // ctrl.isUserResults = $state.current.name === 'userResults';
+        // need auth to browse
         ctrl.isUserResults = $state.current.name === 'userResults';
 
         // Should only be on user-results-page if authenticated.
             'The most recently uploaded community test results are listed ' +
             'here.';
 
+        ctrl.uploadState = '';
+
+        ctrl.isPublic = false;
+
         if (ctrl.isUserResults) {
             ctrl.authRequest = $scope.auth.doSignCheck()
                 .then(ctrl.update);
-            ctrl.getUserProducts();
+            // ctrl.getUserProducts();
         } else {
             ctrl.update();
         }
 
+
+        function uploadFileToUrl(file, uploadUrl){
+           var fd = new FormData();
+           fd.append('file', file);
+           fd.append('public', ctrl.isPublic)
+
+           $http.post(uploadUrl, fd, {
+              transformRequest: angular.identity,
+              headers: {'Content-Type': undefined}
+           })
+
+           .success(function(data){
+              var id = data.href.substr(data.href.lastIndexOf('/')+1);
+              ctrl.uploadState = "Upload succeed. Result id is " + id;
+              ctrl.update();
+           })
+
+           .error(function(data, status){
+              ctrl.uploadState = "Upload failed. Error code is " + status;
+           });
+        }
+
+        function uploadFile(){
+           var file = $scope.resultFile;
+           console.log('file is ' );
+           console.dir(file);
+
+           var uploadUrl = testapiApiUrl + "/results/upload";
+           uploadFileToUrl(file, uploadUrl);
+        };
+
         /**
          * This will contact the TestAPI API to get a listing of test run
          * results.
index 9fdd85f..5d48c7b 100644 (file)
@@ -1 +1 @@
-{"testapiApiUrl": "http://testresults.opnfv.org/test/api/v1"}
+{"testapiApiUrl": "http://localhost:8000/api/v1"}
index 46ccc61..2d7399f 100644 (file)
@@ -40,7 +40,7 @@
         <script src="testapi-ui/shared/header/headerController.js"></script>
         <script src="testapi-ui/shared/alerts/alertModalFactory.js"></script>
         <script src="testapi-ui/shared/alerts/confirmModalFactory.js"></script>
-        <script src="testapi-ui/components/guidelines/guidelinesController.js"></script>
+        <script src="testapi-ui/components/pods/podsController.js"></script>
         <script src="testapi-ui/components/results/resultsController.js"></script>
         <script src="testapi-ui/components/results-report/resultsReportController.js"></script>
         <script src="testapi-ui/components/profile/profileController.js"></script>
index f2c49e8..f5b2414 100644 (file)
@@ -17,7 +17,7 @@ TestAPI
           <ul class="nav navbar-nav">
             <li ng-class="{ active: header.isActive('/')}"><a ui-sref="home">Home</a></li>
             <li ng-class="{ active: header.isActive('/about')}"><a ui-sref="about">About</a></li>
-            <li ng-class="{ active: header.isActive('/guidelines')}"><a ui-sref="guidelines">OPNFV Powered&#8482; Guidelines</a></li>
+            <li ng-class="{ active: header.isActive('/pods')}"><a ui-sref="pods">Pods</a></li>
             <li ng-class="{ active: header.isActive('/community_results')}"><a ui-sref="communityResults">Community Results</a></li>
             <!--
             <li ng-class="{ active: header.isCatalogActive('public')}" class="dropdown" uib-dropdown>
@@ -33,6 +33,7 @@ TestAPI
           </ul>
           <ul class="nav navbar-nav navbar-right">
             <li ng-class="{ active: header.isActive('/user_results')}" ng-if="auth.isAuthenticated"><a ui-sref="userResults">My Results</a></li>
+            <!--
             <li ng-if="auth.isAuthenticated" ng-class="{ active: header.isCatalogActive('user')}" class="dropdown" uib-dropdown>
                 <a role="button" class="dropdown-toggle" uib-dropdown-toggle>
                     My Catalog <strong class="caret"></strong>
@@ -42,6 +43,7 @@ TestAPI
                     <li><a ui-sref="userProducts">My Products</a></li>
                 </ul>
             </li>
+            -->
             <li ng-class="{ active: header.isActive('/profile')}" ng-if="auth.isAuthenticated"><a ui-sref="profile">Profile</a></li>
             <li ng-if="auth.isAuthenticated"><a href="" ng-click="auth.doSignOut()">Sign Out</a></li>
             <li ng-if="!auth.isAuthenticated"><a href="" ng-click="auth.doSignIn()">Sign In / Sign Up</a></li>
diff --git a/utils/test/testapi/MANIFEST.in b/utils/test/testapi/MANIFEST.in
new file mode 100644 (file)
index 0000000..0ba1808
--- /dev/null
@@ -0,0 +1 @@
+recursive-include 3rd_party
\ No newline at end of file
index 748bd34..6433fa6 100644 (file)
@@ -8,10 +8,10 @@ docker_compose_yml = './docker-compose.yml'
 docker_compose_template = './docker-compose.yml.template'
 
 
-def render_docker_compose(port, swagger_url):
+def render_docker_compose(port, base_url):
     vars = {
         "expose_port": port,
-        "swagger_url": swagger_url,
+        "base_url": base_url,
     }
     template = env.get_template(docker_compose_template)
     yml = template.render(vars=vars)
@@ -22,7 +22,7 @@ def render_docker_compose(port, swagger_url):
 
 
 def main(args):
-    render_docker_compose(args.expose_port, args.swagger_url)
+    render_docker_compose(args.expose_port, args.base_url)
     os.system('docker-compose -f {} up -d'.format(docker_compose_yml))
 
 
@@ -33,8 +33,8 @@ if __name__ == '__main__':
                         required=False,
                         default=8000,
                         help='testapi exposed port')
-    parser.add_argument('-su', '--swagger-url',
+    parser.add_argument('-l', '--base-url',
                         type=str,
                         required=True,
-                        help='testapi exposed swagger-url')
+                        help='testapi exposed base-url')
     main(parser.parse_args())
index 5b131f7..cd68404 100644 (file)
@@ -8,7 +8,7 @@ services:
     container_name: opnfv-testapi
     environment:
       - mongodb_url=mongodb://mongo:27017/
-      - swagger_url={{ vars.swagger_url }}
+      - base_url={{ vars.base_url }}
     ports:
       - "{{ vars.expose_port }}:8000"
     links:
index e031e19..a46fce2 100644 (file)
@@ -9,7 +9,7 @@
 #
 # Execution:
 #    $ docker run -dti -p 8001:8000 \
-#      -e "swagger_url=http://10.63.243.17:8001" \
+#      -e "base_url=http://10.63.243.17:8001" \
 #      -e "mongodb_url=mongodb://10.63.243.17:27017/" \
 #      opnfv/testapi:tag
 #
@@ -47,5 +47,5 @@ RUN git clone https://gerrit.opnfv.org/gerrit/releng /home/releng
 
 WORKDIR /home/releng/utils/test/testapi/
 RUN pip install -r requirements.txt
-RUN bash install.sh
+RUN python setup.py install
 CMD ["bash", "docker/start-server.sh"]
index 9f07efb..92a0c9f 100755 (executable)
@@ -6,6 +6,9 @@ if [ "$mongodb_url" != "" ]; then
     sudo crudini --set --existing $FILE mongo url $mongodb_url
 fi
 
-if [ "$swagger_url" != "" ]; then
-    sudo crudini --set --existing $FILE swagger base_url $swagger_url
+if [ "$base_url" != "" ]; then
+    sudo crudini --set --existing $FILE api url $base_url/api/v1
+    sudo crudini --set --existing $FILE ui url $base_url
+    sudo echo "{\"testapiApiUrl\": \"$base_url/api/v1\"}" > \
+        /usr/local/share/opnfv_testapi/testapi-ui/config.json
 fi
index dad59d2..8d0bde2 100644 (file)
@@ -8,64 +8,24 @@ dbname = test_results_collection
 
 [api]
 # Listening port
-url = http://testresults.opnfv.org/test/api/v1
+url = http://localhost:8000/api/v1
 port = 8000
 
 # Number of results for one page (integer value)
-#results_per_page = 20
+results_per_page = 20
 
 # With debug_on set to true, error traces will be shown in HTTP responses
 debug = True
 authenticate = False
 
-[swagger]
-base_url = http://localhost:8000
-
 [ui]
-url = http://testresults.opnfv.org/test
-
-[osid]
-
-# OpenStackID Auth Server URI. (string value)
-openstack_openid_endpoint = https://openstackid.org/accounts/openid2
-
-# OpenStackID logout URI. (string value)
-openid_logout_endpoint = https://openstackid.org/accounts/user/logout
-
-# Interaction mode. Specifies whether Openstack Id IdP may interact
-# with the user to determine the outcome of the request. (string
-# value)
-openid_mode = checkid_setup
-
-# Protocol version. Value identifying the OpenID protocol version
-# being used. This value should be "http://specs.openid.net/auth/2.0".
-# (string value)
-openid_ns = http://specs.openid.net/auth/2.0
-
-# Return endpoint in Refstack's API. Value indicating the endpoint
-# where the user should be returned to after signing in. Openstack Id
-# Idp only supports HTTPS address types. (string value)
-openid_return_to = v1/auth/signin_return
-
-# Claimed identifier. This value must be set to
-# "http://specs.openid.net/auth/2.0/identifier_select". or to user
-# claimed identity (user local identifier or user owned identity [ex:
-# custom html hosted on a owned domain set to html discover]). (string
-# value)
-openid_claimed_id = http://specs.openid.net/auth/2.0/identifier_select
-
-# Alternate identifier. This value must be set to
-# http://specs.openid.net/auth/2.0/identifier_select. (string value)
-openid_identity = http://specs.openid.net/auth/2.0/identifier_select
+url = http://localhost:8000
 
-# Indicates request for user attribute information. This value must be
-# set to "http://openid.net/extensions/sreg/1.1". (string value)
-openid_ns_sreg = http://openid.net/extensions/sreg/1.1
+# this path should be the seem with data_files installation path
+static_path = /usr/local/share/opnfv_testapi
 
-# Comma-separated list of field names which, if absent from the
-# response, will prevent the Consumer from completing the registration
-# without End User interation. The field names are those that are
-# specified in the Response Format, with the "openid.sreg." prefix
-# removed. Valid values include: "country", "email", "firstname",
-# "language", "lastname" (string value)
-openid_sreg_required = email,fullname
+[lfid]
+# Linux Foundation cas URL
+cas_url = https://identity.linuxfoundation.org/cas/
+#service url used to authenticate to cas
+signin_return = api/v1/auth/signin_return
index 4576d9b..da6a6cf 100644 (file)
@@ -33,6 +33,7 @@ def main(args):
     else:
         exit(1)
 
+
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='Create \
                                       Swagger Spec documentation')
diff --git a/utils/test/testapi/install.sh b/utils/test/testapi/install.sh
deleted file mode 100755 (executable)
index d470e38..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-usage="
-Script to install opnfv_tesgtapi automatically.
-This script should be run under root.
-
-usage:
-    bash $(basename "$0") [-h|--help] [-t <test_name>]
-
-where:
-    -h|--help         show this help text"
-
-# Ref :-  https://openstack.nimeyo.com/87286/openstack-packaging-all-definition-data-files-config-setup
-if [ -z "$VIRTUAL_ENV" ];
-then
-    if [[ $(whoami) != "root" ]];
-    then
-        echo "Error: This script must be run as root!"
-        exit 1
-    fi
-else
-    sed -i -e 's#/etc/opnfv_testapi =#etc/opnfv_testapi =#g' setup.cfg
-fi
-
-cp -fr 3rd_party/static opnfv_testapi/static
-python setup.py install
-rm -fr opnfv_testapi/static
-if [ ! -z "$VIRTUAL_ENV" ]; then
-    sed -i -e 's#etc/opnfv_testapi =#/etc/opnfv_testapi =#g' setup.cfg
-fi
\ No newline at end of file
index 545d5e3..b7d3caa 100644 (file)
@@ -29,40 +29,18 @@ TODOs :
 
 """
 
-import argparse
-import sys
-
-import motor
 import tornado.ioloop
 
-from opnfv_testapi.common import config
+from opnfv_testapi.common.config import CONF
 from opnfv_testapi.router import url_mappings
 from opnfv_testapi.tornado_swagger import swagger
 
-CONF = None
-
-
-def parse_config(argv=[]):
-    global CONF
-    parser = argparse.ArgumentParser()
-    parser.add_argument("-c", "--config-file", dest='config_file',
-                        help="Config file location")
-    args = parser.parse_args(argv)
-    if args.config_file:
-        config.Config.CONFIG = args.config_file
-    CONF = config.Config()
-
-
-def get_db():
-    return motor.MotorClient(CONF.mongo_url)[CONF.mongo_dbname]
-
 
 def make_app():
-    swagger.docs(base_url=CONF.swagger_base_url,
-                 static_path=CONF.static_path)
+    swagger.docs(base_url=CONF.ui_url,
+                 static_path=CONF.ui_static_path)
     return swagger.Application(
         url_mappings.mappings,
-        db=get_db(),
         debug=CONF.api_debug,
         auth=CONF.api_authenticate,
         cookie_secret='opnfv-testapi',
@@ -70,7 +48,6 @@ def make_app():
 
 
 def main():
-    parse_config(sys.argv[1:])
     application = make_app()
     application.listen(CONF.api_port)
     tornado.ioloop.IOLoop.current().start()
index 67e8fbd..24ba876 100644 (file)
@@ -13,6 +13,7 @@ from tornado import web
 
 from opnfv_testapi.common import message
 from opnfv_testapi.common import raises
+from opnfv_testapi.db import api as dbapi
 
 
 def authenticate(method):
@@ -26,7 +27,7 @@ def authenticate(method):
             except KeyError:
                 raises.Unauthorized(message.unauthorized())
             query = {'access_token': token}
-            check = yield self._eval_db_find_one(query, 'tokens')
+            check = yield dbapi.db_find_one('tokens', query)
             if not check:
                 raises.Forbidden(message.invalid_token())
         ret = yield gen.coroutine(method)(self, *args, **kwargs)
@@ -38,7 +39,7 @@ def not_exist(xstep):
     @functools.wraps(xstep)
     def wrap(self, *args, **kwargs):
         query = kwargs.get('query')
-        data = yield self._eval_db_find_one(query)
+        data = yield dbapi.db_find_one(self.table, query)
         if not data:
             raises.NotFound(message.not_found(self.table, query))
         ret = yield gen.coroutine(xstep)(self, data, *args, **kwargs)
@@ -78,7 +79,7 @@ def carriers_exist(xstep):
         carriers = kwargs.pop('carriers', {})
         if carriers:
             for table, query in carriers:
-                exist = yield self._eval_db_find_one(query(), table)
+                exist = yield dbapi.db_find_one(table, query())
                 if not exist:
                     raises.Forbidden(message.not_found(table, query()))
         ret = yield gen.coroutine(xstep)(self, *args, **kwargs)
@@ -91,7 +92,7 @@ def new_not_exists(xstep):
     def wrap(self, *args, **kwargs):
         query = kwargs.get('query')
         if query:
-            to_data = yield self._eval_db_find_one(query())
+            to_data = yield dbapi.db_find_one(self.table, query())
             if to_data:
                 raises.Forbidden(message.exist(self.table, query()))
         ret = yield gen.coroutine(xstep)(self, *args, **kwargs)
@@ -105,7 +106,7 @@ def updated_one_not_exist(xstep):
         db_keys = kwargs.pop('db_keys', [])
         query = self._update_query(db_keys, data)
         if query:
-            to_data = yield self._eval_db_find_one(query)
+            to_data = yield dbapi.db_find_one(self.table, query)
             if to_data:
                 raises.Forbidden(message.exist(self.table, query))
         ret = yield gen.coroutine(xstep)(self, data, *args, **kwargs)
index f73c0ab..140e492 100644 (file)
@@ -8,27 +8,25 @@
 # feng.xiaowei@zte.com.cn remove prepare_put_request            5-30-2016
 ##############################################################################
 import ConfigParser
+import argparse
 import os
+import sys
 
 
 class Config(object):
-    CONFIG = None
 
     def __init__(self):
-        self.file = self.CONFIG if self.CONFIG else self._default_config()
+        self.config_file = '/etc/opnfv_testapi/config.ini'
+        self._set_config_file()
         self._parse()
         self._parse_per_page()
-        self.static_path = os.path.join(
-            os.path.dirname(os.path.normpath(__file__)),
-            os.pardir,
-            'static')
 
     def _parse(self):
-        if not os.path.exists(self.file):
-            raise Exception("%s not found" % self.file)
+        if not os.path.exists(self.config_file):
+            raise Exception("%s not found" % self.config_file)
 
         config = ConfigParser.RawConfigParser()
-        config.read(self.file)
+        config.read(self.config_file)
         self._parse_section(config)
 
     def _parse_section(self, config):
@@ -53,8 +51,13 @@ class Config(object):
                 value = False
         return value
 
-    @staticmethod
-    def _default_config():
-        is_venv = os.getenv('VIRTUAL_ENV')
-        return os.path.join('/' if not is_venv else is_venv,
-                            'etc/opnfv_testapi/config.ini')
+    def _set_config_file(self):
+        parser = argparse.ArgumentParser()
+        parser.add_argument("-c", "--config-file", dest='config_file',
+                            help="Config file location", metavar="FILE")
+        args, _ = parser.parse_known_args(sys.argv)
+        if hasattr(args, 'config_file') and args.config_file:
+            self.config_file = args.config_file
+
+
+CONF = Config()
diff --git a/utils/test/testapi/opnfv_testapi/common/constants.py b/utils/test/testapi/opnfv_testapi/common/constants.py
new file mode 100644 (file)
index 0000000..70c9223
--- /dev/null
@@ -0,0 +1,4 @@
+TESTAPI_ID = 'testapi_id'
+CSRF_TOKEN = 'csrf_token'
+ROLE = 'role'
+TESTAPI_USERS = ['opnfv-testapi-users']
index 98536ff..951cbaf 100644 (file)
@@ -10,6 +10,10 @@ not_found_base = 'Could Not Found'
 exist_base = 'Already Exists'
 
 
+def key_error(key):
+    return "KeyError: '{}'".format(key)
+
+
 def no_body():
     return 'No Body'
 
index ec6b8a5..55c58c9 100644 (file)
@@ -26,6 +26,10 @@ class Forbidden(Raiser):
     code = httplib.FORBIDDEN
 
 
+class Conflict(Raiser):
+    code = httplib.CONFLICT
+
+
 class NotFound(Raiser):
     code = httplib.NOT_FOUND
 
diff --git a/utils/test/testapi/opnfv_testapi/db/__init__.py b/utils/test/testapi/opnfv_testapi/db/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/utils/test/testapi/opnfv_testapi/db/api.py b/utils/test/testapi/opnfv_testapi/db/api.py
new file mode 100644 (file)
index 0000000..c057480
--- /dev/null
@@ -0,0 +1,38 @@
+import motor
+
+from opnfv_testapi.common.config import CONF
+
+DB = motor.MotorClient(CONF.mongo_url)[CONF.mongo_dbname]
+
+
+def db_update(collection, query, update_req):
+    return _eval_db(collection, 'update', query, update_req, check_keys=False)
+
+
+def db_delete(collection, query):
+    return _eval_db(collection, 'remove', query)
+
+
+def db_aggregate(collection, pipelines):
+    return _eval_db(collection, 'aggregate', pipelines, allowDiskUse=True)
+
+
+def db_list(collection, query):
+    return _eval_db(collection, 'find', query)
+
+
+def db_save(collection, data):
+    return _eval_db(collection, 'insert', data, check_keys=False)
+
+
+def db_find_one(collection, query):
+    return _eval_db(collection, 'find_one', query)
+
+
+def _eval_db(collection, method, *args, **kwargs):
+    exec_collection = DB.__getattr__(collection)
+    return exec_collection.__getattribute__(method)(*args, **kwargs)
+
+
+def _eval_db_find_one(query, table=None):
+    return _eval_db(table, 'find_one', query)
index c7fed8f..ed55c70 100644 (file)
@@ -20,8 +20,8 @@
 # feng.xiaowei@zte.com.cn remove DashboardHandler            5-30-2016
 ##############################################################################
 
-from datetime import datetime
 import json
+from datetime import datetime
 
 from tornado import gen
 from tornado import web
@@ -29,6 +29,7 @@ from tornado import web
 from opnfv_testapi.common import check
 from opnfv_testapi.common import message
 from opnfv_testapi.common import raises
+from opnfv_testapi.db import api as dbapi
 from opnfv_testapi.resources import models
 from opnfv_testapi.tornado_swagger import swagger
 
@@ -38,7 +39,6 @@ DEFAULT_REPRESENTATION = "application/json"
 class GenericApiHandler(web.RequestHandler):
     def __init__(self, application, request, **kwargs):
         super(GenericApiHandler, self).__init__(application, request, **kwargs)
-        self.db = self.settings["db"]
         self.json_args = None
         self.table = None
         self.table_cls = None
@@ -50,7 +50,7 @@ class GenericApiHandler(web.RequestHandler):
         self.auth = self.settings["auth"]
 
     def prepare(self):
-        if self.request.method != "GET" and self.request.method != "DELETE":
+        if self.request.body:
             if self.request.headers.get("Content-Type") is not None:
                 if self.request.headers["Content-Type"].startswith(
                         DEFAULT_REPRESENTATION):
@@ -90,8 +90,7 @@ class GenericApiHandler(web.RequestHandler):
 
         if self.table != 'results':
             data.creation_date = datetime.now()
-        _id = yield self._eval_db(self.table, 'insert', data.format(),
-                                  check_keys=False)
+        _id = yield dbapi.db_save(self.table, data.format())
         if 'name' in self.json_args:
             resource = data.name
         else:
@@ -107,25 +106,32 @@ class GenericApiHandler(web.RequestHandler):
         per_page = kwargs.get('per_page', 0)
         if query is None:
             query = {}
-        cursor = self._eval_db(self.table, 'find', query)
-        records_count = yield cursor.count()
-        total_pages = self._calc_total_pages(records_count,
-                                             last,
-                                             page,
-                                             per_page)
-        pipelines = self._set_pipelines(query, sort, last, page, per_page)
-        cursor = self._eval_db(self.table,
-                               'aggregate',
-                               pipelines,
-                               allowDiskUse=True)
+        pipelines = list()
+        pipelines.append({'$match': query})
+
+        total_pages = 0
         data = list()
-        while (yield cursor.fetch_next):
-            data.append(self.format_data(cursor.next_object()))
+        cursor = dbapi.db_list(self.table, query)
+        records_count = yield cursor.count()
+        if records_count > 0:
+            if page > 0:
+                total_pages, return_nr = self._calc_total_pages(records_count,
+                                                                last,
+                                                                page,
+                                                                per_page)
+                pipelines = self._set_pipelines(pipelines,
+                                                sort,
+                                                return_nr,
+                                                page,
+                                                per_page)
+            cursor = dbapi.db_aggregate(self.table, pipelines)
+            while (yield cursor.fetch_next):
+                data.append(self.format_data(cursor.next_object()))
         if res_op is None:
             res = {self.table: data}
         else:
             res = res_op(data, *args)
-        if total_pages > 0:
+        if page > 0:
             res.update({
                 'pagination': {
                     'current_page': kwargs.get('page'),
@@ -140,29 +146,23 @@ class GenericApiHandler(web.RequestHandler):
         if (records_count > last) and (last > 0):
             records_nr = last
 
-        total_pages = 0
-        if page > 0:
-            total_pages, remainder = divmod(records_nr, per_page)
-            if remainder > 0:
-                total_pages += 1
-        if page > total_pages:
+        total_pages, remainder = divmod(records_nr, per_page)
+        if remainder > 0:
+            total_pages += 1
+        if page > 1 and page > total_pages:
             raises.BadRequest(
                 'Request page > total_pages [{}]'.format(total_pages))
-        return total_pages
+        return total_pages, records_nr
 
     @staticmethod
-    def _set_pipelines(query, sort, last, page, per_page):
-        pipelines = list()
-        if query:
-            pipelines.append({'$match': query})
+    def _set_pipelines(pipelines, sort, return_nr, page, per_page):
         if sort:
             pipelines.append({'$sort': sort})
 
-        if page > 0:
-            pipelines.append({'$skip': (page - 1) * per_page})
-            pipelines.append({'$limit': per_page})
-        elif last > 0:
-            pipelines.append({'$limit': last})
+        over = (page - 1) * per_page
+        left = return_nr - over
+        pipelines.append({'$skip': over})
+        pipelines.append({'$limit': per_page if per_page < left else left})
 
         return pipelines
 
@@ -175,7 +175,7 @@ class GenericApiHandler(web.RequestHandler):
     @check.authenticate
     @check.not_exist
     def _delete(self, data, query=None):
-        yield self._eval_db(self.table, 'remove', query)
+        yield dbapi.db_delete(self.table, query)
         self.finish_request()
 
     @check.authenticate
@@ -185,11 +185,20 @@ class GenericApiHandler(web.RequestHandler):
     def _update(self, data, query=None, **kwargs):
         data = self.table_cls.from_dict(data)
         update_req = self._update_requests(data)
-        yield self._eval_db(self.table, 'update', query, update_req,
-                            check_keys=False)
+        yield dbapi.db_update(self.table, query, update_req)
         update_req['_id'] = str(data._id)
         self.finish_request(update_req)
 
+    @check.authenticate
+    @check.no_body
+    @check.not_exist
+    @check.updated_one_not_exist
+    def pure_update(self, data, query=None, **kwargs):
+        data = self.table_cls.from_dict(data)
+        update_req = self._update_requests(data)
+        yield dbapi.db_update(self.table, query, update_req)
+        self.finish_request()
+
     def _update_requests(self, data):
         request = dict()
         for k, v in self.json_args.iteritems():
@@ -229,23 +238,6 @@ class GenericApiHandler(web.RequestHandler):
             query[key] = new
         return query if not equal else dict()
 
-    def _eval_db(self, table, method, *args, **kwargs):
-        exec_collection = self.db.__getattr__(table)
-        return exec_collection.__getattribute__(method)(*args, **kwargs)
-
-    def _eval_db_find_one(self, query, table=None):
-        if table is None:
-            table = self.table
-        return self._eval_db(table, 'find_one', query)
-
-    def db_save(self, collection, data):
-        self._eval_db(collection, 'insert', data, check_keys=False)
-
-    def db_find_one(self, query, collection=None):
-        if not collection:
-            collection = self.table
-        return self._eval_db(collection, 'find_one', query)
-
 
 class VersionHandler(GenericApiHandler):
     @swagger.operation(nickname='listAllVersions')
index e8fc532..e70a6ed 100644 (file)
@@ -48,6 +48,29 @@ class ModelBase(object):
 
         return t
 
+    @classmethod
+    def from_dict_with_raise(cls, a_dict):
+        if a_dict is None:
+            return None
+
+        attr_parser = cls.attr_parser()
+        t = cls()
+        for k, v in a_dict.iteritems():
+            if k not in t.__dict__:
+                raise AttributeError(
+                    '{} has no attribute {}'.format(cls.__name__, k))
+            value = v
+            if isinstance(v, dict) and k in attr_parser:
+                value = attr_parser[k].from_dict_with_raise(v)
+            elif isinstance(v, list) and k in attr_parser:
+                value = []
+                for item in v:
+                    value.append(attr_parser[k].from_dict_with_raise(item))
+
+            t.__setattr__(k, value)
+
+        return t
+
     @staticmethod
     def attr_parser():
         return {}
index 1773216..e202f5c 100644 (file)
@@ -6,20 +6,21 @@
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
-from datetime import datetime
-from datetime import timedelta
+import json
+import logging
 
 from bson import objectid
+from datetime import datetime
+from datetime import timedelta
 
-from opnfv_testapi.common import config
+from opnfv_testapi.common import constants
 from opnfv_testapi.common import message
 from opnfv_testapi.common import raises
+from opnfv_testapi.common.config import CONF
 from opnfv_testapi.resources import handlers
 from opnfv_testapi.resources import result_models
 from opnfv_testapi.tornado_swagger import swagger
 
-CONF = config.Config()
-
 
 class GenericResultHandler(handlers.GenericApiHandler):
     def __init__(self, application, request, **kwargs):
@@ -40,6 +41,7 @@ class GenericResultHandler(handlers.GenericApiHandler):
         query = dict()
         date_range = dict()
 
+        query['public'] = {'$not': {'$eq': 'false'}}
         for k in self.request.query_arguments.keys():
             v = self.get_query_argument(k)
             if k == 'project' or k == 'pod' or k == 'case':
@@ -56,10 +58,23 @@ class GenericResultHandler(handlers.GenericApiHandler):
                 date_range.update({'$gte': str(v)})
             elif k == 'to':
                 date_range.update({'$lt': str(v)})
-            elif k != 'last' and k != 'page':
+            elif k == 'signed':
+                username = self.get_secure_cookie(constants.TESTAPI_ID)
+                role = self.get_secure_cookie(constants.ROLE)
+                if role:
+                    del query['public']
+                    if role != "reviewer":
+                        query['user'] = username
+            elif k not in ['last', 'page', 'descend']:
                 query[k] = v
             if date_range:
                 query['start_date'] = date_range
+
+            # if $lt is not provided,
+            # empty/None/null/'' start_date will also be returned
+            if 'start_date' in query and '$lt' not in query['start_date']:
+                query['start_date'].update({'$lt': str(datetime.now())})
+
         return query
 
 
@@ -84,9 +99,10 @@ class ResultsCLHandler(GenericResultHandler):
                  - criteria : the global criteria status passed or failed
                  - trust_indicator : evaluate the stability of the test case
                    to avoid running systematically long and stable test case
+                 - signed : get logined user result
 
                 GET /results/project=functest&case=vPing&version=Arno-R1 \
-                &pod=pod_name&period=15
+                &pod=pod_name&period=15&signed
             @return 200: all test results consist with query,
                          empty list if no result is found
             @rtype: L{TestResults}
@@ -138,7 +154,7 @@ class ResultsCLHandler(GenericResultHandler):
             @type last: L{string}
             @in last: query
             @required last: False
-            @param page: which page to list
+            @param page: which page to list, default to 1
             @type page: L{int}
             @in page: query
             @required page: False
@@ -146,18 +162,31 @@ class ResultsCLHandler(GenericResultHandler):
             @type trust_indicator: L{float}
             @in trust_indicator: query
             @required trust_indicator: False
+            @param signed: user results or all results
+            @type signed: L{string}
+            @in signed: query
+            @required signed: False
+            @param descend: true, newest2oldest; false, oldest2newest
+            @type descend: L{string}
+            @in descend: query
+            @required descend: False
         """
-        limitations = {'sort': {'start_date': -1}}
-        last = self.get_query_argument('last', 0)
-        if last is not None:
-            last = self.get_int('last', last)
-            limitations.update({'last': last})
-
-        page = self.get_query_argument('page', None)
-        if page is not None:
-            page = self.get_int('page', page)
-            limitations.update({'page': page,
-                                'per_page': CONF.api_results_per_page})
+        def descend_limit():
+            descend = self.get_query_argument('descend', 'true')
+            return -1 if descend.lower() == 'true' else 1
+
+        def last_limit():
+            return self.get_int('last', self.get_query_argument('last', 0))
+
+        def page_limit():
+            return self.get_int('page', self.get_query_argument('page', 1))
+
+        limitations = {
+            'sort': {'_id': descend_limit()},
+            'last': last_limit(),
+            'page': page_limit(),
+            'per_page': CONF.api_results_per_page
+        }
 
         self._list(query=self.set_query(), **limitations)
 
@@ -173,6 +202,9 @@ class ResultsCLHandler(GenericResultHandler):
             @raise 404: pod/project/testcase not exist
             @raise 400: body/pod_name/project_name/case_name not provided
         """
+        self._post()
+
+    def _post(self):
         def pod_query():
             return {'name': self.json_args.get('pod_name')}
 
@@ -187,9 +219,39 @@ class ResultsCLHandler(GenericResultHandler):
         carriers = [('pods', pod_query),
                     ('projects', project_query),
                     ('testcases', testcase_query)]
+
         self._create(miss_fields=miss_fields, carriers=carriers)
 
 
+class ResultsUploadHandler(ResultsCLHandler):
+    @swagger.operation(nickname="uploadTestResult")
+    def post(self):
+        """
+            @description: upload and create a test result
+            @param body: result to be created
+            @type body: L{ResultCreateRequest}
+            @in body: body
+            @rtype: L{CreateResponse}
+            @return 200: result is created.
+            @raise 404: pod/project/testcase not exist
+            @raise 400: body/pod_name/project_name/case_name not provided
+        """
+        logging.info('file upload')
+        fileinfo = self.request.files['file'][0]
+        is_public = self.get_body_argument('public')
+        logging.warning('public:%s', is_public)
+        logging.info('results is :%s', fileinfo['filename'])
+        logging.info('results is :%s', fileinfo['body'])
+        self.json_args = json.loads(fileinfo['body']).copy()
+        self.json_args['public'] = is_public
+
+        openid = self.get_secure_cookie(constants.TESTAPI_ID)
+        if openid:
+            self.json_args['user'] = openid
+
+        super(ResultsUploadHandler, self)._post()
+
+
 class ResultsGURHandler(GenericResultHandler):
     @swagger.operation(nickname='getTestResultById')
     def get(self, result_id):
index 62a6dac..890bf82 100644 (file)
@@ -54,6 +54,8 @@ class ResultCreateRequest(models.ModelBase):
                  build_tag=None,
                  scenario=None,
                  criteria=None,
+                 user=None,
+                 public="true",
                  trust_indicator=None):
         self.pod_name = pod_name
         self.project_name = project_name
@@ -66,6 +68,8 @@ class ResultCreateRequest(models.ModelBase):
         self.build_tag = build_tag
         self.scenario = scenario
         self.criteria = criteria
+        self.user = user
+        self.public = public
         self.trust_indicator = trust_indicator if trust_indicator else TI(0)
 
 
@@ -89,7 +93,7 @@ class TestResult(models.ModelBase):
                  pod_name=None, installer=None, version=None,
                  start_date=None, stop_date=None, details=None,
                  build_tag=None, scenario=None, criteria=None,
-                 trust_indicator=None):
+                 user=None, public="true", trust_indicator=None):
         self._id = _id
         self.case_name = case_name
         self.project_name = project_name
@@ -102,6 +106,8 @@ class TestResult(models.ModelBase):
         self.build_tag = build_tag
         self.scenario = scenario
         self.criteria = criteria
+        self.user = user
+        self.public = public
         self.trust_indicator = trust_indicator
 
     @staticmethod
index 5d420a5..e9c19a7 100644 (file)
@@ -15,6 +15,24 @@ class GenericScenarioHandler(handlers.GenericApiHandler):
         self.table = self.db_scenarios
         self.table_cls = models.Scenario
 
+    def set_query(self, locators):
+        query = dict()
+        elem_query = dict()
+        for k, v in locators.iteritems():
+            if k == 'scenario':
+                query['name'] = v
+            elif k == 'installer':
+                elem_query["installer"] = v
+            elif k == 'version':
+                elem_query["versions.version"] = v
+            elif k == 'project':
+                elem_query["versions.projects.project"] = v
+            else:
+                query[k] = v
+        if elem_query:
+            query['installers'] = {'$elemMatch': elem_query}
+        return query
+
 
 class ScenariosCLHandler(GenericScenarioHandler):
     @swagger.operation(nickname="queryScenarios")
@@ -96,10 +114,10 @@ class ScenarioGURHandler(GenericScenarioHandler):
         self._get_one(query={'name': name})
         pass
 
-    @swagger.operation(nickname="updateScenarioByName")
+    @swagger.operation(nickname="updateScenarioName")
     def put(self, name):
         """
-            @description: update a single scenario by name
+            @description: update scenario, only rename is supported currently
             @param body: fields to be updated
             @type body: L{ScenarioUpdateRequest}
             @in body: body
@@ -119,164 +137,639 @@ class ScenarioGURHandler(GenericScenarioHandler):
         @return 200: delete success
         @raise 404: scenario not exist:
         """
-
         self._delete(query={'name': name})
 
-    def _update_query(self, keys, data):
-        query = dict()
-        if self._is_rename():
-            new = self._term.get('name')
-            if data.get('name') != new:
-                query['name'] = new
 
-        return query
+class ScenarioUpdater(object):
+    def __init__(self, data, body=None,
+                 installer=None, version=None, project=None):
+        self.data = data
+        self.body = body
+        self.installer = installer
+        self.version = version
+        self.project = project
 
-    def _update_requests(self, data):
+    def update(self, item, action):
         updates = {
-            ('name', 'update'): self._update_requests_rename,
-            ('installer', 'add'): self._update_requests_add_installer,
-            ('installer', 'delete'): self._update_requests_delete_installer,
-            ('version', 'add'): self._update_requests_add_version,
-            ('version', 'delete'): self._update_requests_delete_version,
-            ('owner', 'update'): self._update_requests_change_owner,
-            ('project', 'add'): self._update_requests_add_project,
-            ('project', 'delete'): self._update_requests_delete_project,
-            ('customs', 'add'): self._update_requests_add_customs,
+            ('scores', 'post'): self._update_requests_add_score,
+            ('trust_indicators', 'post'): self._update_requests_add_ti,
+            ('customs', 'post'): self._update_requests_add_customs,
+            ('customs', 'put'): self._update_requests_update_customs,
             ('customs', 'delete'): self._update_requests_delete_customs,
-            ('score', 'add'): self._update_requests_add_score,
-            ('trust_indicator', 'add'): self._update_requests_add_ti,
+            ('projects', 'post'): self._update_requests_add_projects,
+            ('projects', 'put'): self._update_requests_update_projects,
+            ('projects', 'delete'): self._update_requests_delete_projects,
+            ('owner', 'put'): self._update_requests_change_owner,
+            ('versions', 'post'): self._update_requests_add_versions,
+            ('versions', 'put'): self._update_requests_update_versions,
+            ('versions', 'delete'): self._update_requests_delete_versions,
+            ('installers', 'post'): self._update_requests_add_installers,
+            ('installers', 'put'): self._update_requests_update_installers,
+            ('installers', 'delete'): self._update_requests_delete_installers,
         }
+        updates[(item, action)](self.data)
 
-        updates[(self._field, self._op)](data)
-
-        return data.format()
+        return self.data.format()
 
-    def _iter_installers(xstep):
+    def iter_installers(xstep):
         @functools.wraps(xstep)
         def magic(self, data):
             [xstep(self, installer)
              for installer in self._filter_installers(data.installers)]
         return magic
 
-    def _iter_versions(xstep):
+    def iter_versions(xstep):
         @functools.wraps(xstep)
         def magic(self, installer):
             [xstep(self, version)
              for version in (self._filter_versions(installer.versions))]
         return magic
 
-    def _iter_projects(xstep):
+    def iter_projects(xstep):
         @functools.wraps(xstep)
         def magic(self, version):
             [xstep(self, project)
              for project in (self._filter_projects(version.projects))]
         return magic
 
-    def _update_requests_rename(self, data):
-        data.name = self._term.get('name')
-        if not data.name:
-            raises.BadRequest(message.missing('name'))
-
-    def _update_requests_add_installer(self, data):
-        data.installers.append(models.ScenarioInstaller.from_dict(self._term))
-
-    def _update_requests_delete_installer(self, data):
-        data.installers = self._remove_installers(data.installers)
-
-    @_iter_installers
-    def _update_requests_add_version(self, installer):
-        installer.versions.append(models.ScenarioVersion.from_dict(self._term))
-
-    @_iter_installers
-    def _update_requests_delete_version(self, installer):
-        installer.versions = self._remove_versions(installer.versions)
-
-    @_iter_installers
-    @_iter_versions
-    def _update_requests_change_owner(self, version):
-        version.owner = self._term.get('owner')
-
-    @_iter_installers
-    @_iter_versions
-    def _update_requests_add_project(self, version):
-        version.projects.append(models.ScenarioProject.from_dict(self._term))
+    @iter_installers
+    @iter_versions
+    @iter_projects
+    def _update_requests_add_score(self, project):
+        project.scores.append(
+            models.ScenarioScore.from_dict(self.body))
 
-    @_iter_installers
-    @_iter_versions
-    def _update_requests_delete_project(self, version):
-        version.projects = self._remove_projects(version.projects)
+    @iter_installers
+    @iter_versions
+    @iter_projects
+    def _update_requests_add_ti(self, project):
+        project.trust_indicators.append(
+            models.ScenarioTI.from_dict(self.body))
 
-    @_iter_installers
-    @_iter_versions
-    @_iter_projects
+    @iter_installers
+    @iter_versions
+    @iter_projects
     def _update_requests_add_customs(self, project):
-        project.customs = list(set(project.customs + self._term))
+        project.customs = list(set(project.customs + self.body))
 
-    @_iter_installers
-    @_iter_versions
-    @_iter_projects
+    @iter_installers
+    @iter_versions
+    @iter_projects
+    def _update_requests_update_customs(self, project):
+        project.customs = list(set(self.body))
+
+    @iter_installers
+    @iter_versions
+    @iter_projects
     def _update_requests_delete_customs(self, project):
         project.customs = filter(
-            lambda f: f not in self._term,
+            lambda f: f not in self.body,
             project.customs)
 
-    @_iter_installers
-    @_iter_versions
-    @_iter_projects
-    def _update_requests_add_score(self, project):
-        project.scores.append(
-            models.ScenarioScore.from_dict(self._term))
+    @iter_installers
+    @iter_versions
+    def _update_requests_add_projects(self, version):
+        version.projects = self._update_with_body(models.ScenarioProject,
+                                                  'project',
+                                                  version.projects)
+
+    @iter_installers
+    @iter_versions
+    def _update_requests_update_projects(self, version):
+        version.projects = self._update_with_body(models.ScenarioProject,
+                                                  'project',
+                                                  list())
+
+    @iter_installers
+    @iter_versions
+    def _update_requests_delete_projects(self, version):
+        version.projects = self._remove_projects(version.projects)
 
-    @_iter_installers
-    @_iter_versions
-    @_iter_projects
-    def _update_requests_add_ti(self, project):
-        project.trust_indicators.append(
-            models.ScenarioTI.from_dict(self._term))
+    @iter_installers
+    @iter_versions
+    def _update_requests_change_owner(self, version):
+        version.owner = self.body.get('owner')
+
+    @iter_installers
+    def _update_requests_add_versions(self, installer):
+        installer.versions = self._update_with_body(models.ScenarioVersion,
+                                                    'version',
+                                                    installer.versions)
+
+    @iter_installers
+    def _update_requests_update_versions(self, installer):
+        installer.versions = self._update_with_body(models.ScenarioVersion,
+                                                    'version',
+                                                    list())
+
+    @iter_installers
+    def _update_requests_delete_versions(self, installer):
+        installer.versions = self._remove_versions(installer.versions)
+
+    def _update_requests_add_installers(self, scenario):
+        scenario.installers = self._update_with_body(models.ScenarioInstaller,
+                                                     'installer',
+                                                     scenario.installers)
+
+    def _update_requests_update_installers(self, scenario):
+        scenario.installers = self._update_with_body(models.ScenarioInstaller,
+                                                     'installer',
+                                                     list())
+
+    def _update_requests_delete_installers(self, scenario):
+        scenario.installers = self._remove_installers(scenario.installers)
+
+    def _update_with_body(self, clazz, field, withs):
+        exists = list()
+        malformat = list()
+        for new in self.body:
+            try:
+                format_new = clazz.from_dict_with_raise(new)
+                new_name = getattr(format_new, field)
+                if not any(getattr(o, field) == new_name for o in withs):
+                    withs.append(format_new)
+                else:
+                    exists.append(new_name)
+            except Exception as error:
+                malformat.append(error.message)
+        if malformat:
+            raises.BadRequest(message.bad_format(malformat))
+        elif exists:
+            raises.Conflict(message.exist('{}s'.format(field), exists))
+        return withs
 
-    def _is_rename(self):
-        return self._field == 'name' and self._op == 'update'
+    def _filter_installers(self, installers):
+        return self._filter('installer', installers)
 
     def _remove_installers(self, installers):
         return self._remove('installer', installers)
 
-    def _filter_installers(self, installers):
-        return self._filter('installer', installers)
+    def _filter_versions(self, versions):
+        return self._filter('version', versions)
 
     def _remove_versions(self, versions):
         return self._remove('version', versions)
 
-    def _filter_versions(self, versions):
-        return self._filter('version', versions)
+    def _filter_projects(self, projects):
+        return self._filter('project', projects)
 
     def _remove_projects(self, projects):
         return self._remove('project', projects)
 
-    def _filter_projects(self, projects):
-        return self._filter('project', projects)
+    def _filter(self, item, items):
+        return filter(
+            lambda f: getattr(f, item) == getattr(self, item),
+            items)
 
     def _remove(self, field, fields):
         return filter(
-            lambda f: getattr(f, field) != self._locate.get(field),
+            lambda f: getattr(f, field) not in self.body,
             fields)
 
-    def _filter(self, field, fields):
-        return filter(
-            lambda f: getattr(f, field) == self._locate.get(field),
-            fields)
 
-    @property
-    def _field(self):
-        return self.json_args.get('field')
+class GenericScenarioUpdateHandler(GenericScenarioHandler):
+    def __init__(self, application, request, **kwargs):
+        super(GenericScenarioUpdateHandler, self).__init__(application,
+                                                           request,
+                                                           **kwargs)
+        self.installer = None
+        self.version = None
+        self.project = None
+        self.item = None
+        self.action = None
+
+    def do_update(self, item, action, locators):
+        self.item = item
+        self.action = action
+        for k, v in locators.iteritems():
+            if not v:
+                v = self.get_query_argument(k)
+                setattr(self, k, v)
+                locators[k] = v
+        self.pure_update(query=self.set_query(locators=locators))
+
+    def _update_requests(self, data):
+        return ScenarioUpdater(data,
+                               self.json_args,
+                               self.installer,
+                               self.version,
+                               self.project).update(self.item, self.action)
+
+
+class ScenarioScoresHandler(GenericScenarioUpdateHandler):
+    @swagger.operation(nickname="addScoreRecord")
+    def post(self, scenario):
+        """
+        @description: add a new score record
+        @notes: add a new score record to a project
+            POST /api/v1/scenarios/<scenario_name>/scores? \
+                installer=<installer_name>& \
+                version=<version_name>& \
+                project=<project_name>
+        @param body: score to be added
+        @type body: L{ScenarioScore}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @param version: version
+        @type version: L{string}
+        @in version: query
+        @required version: True
+        @param project: project name
+        @type project: L{string}
+        @in project: query
+        @required project: True
+        @return 200: score is created.
+        @raise 404:  scenario/installer/version/project not existed
+        """
+        self.do_update('scores',
+                       'post',
+                       locators={'scenario': scenario,
+                                 'installer': None,
+                                 'version': None,
+                                 'project': None})
+
+
+class ScenarioTIsHandler(GenericScenarioUpdateHandler):
+    @swagger.operation(nickname="addTrustIndicatorRecord")
+    def post(self, scenario):
+        """
+        @description: add a new trust indicator record
+        @notes: add a new trust indicator record to a project
+            POST /api/v1/scenarios/<scenario_name>/trust_indicators? \
+                installer=<installer_name>& \
+                version=<version_name>& \
+                project=<project_name>
+        @param body: trust indicator to be added
+        @type body: L{ScenarioTI}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @param version: version
+        @type version: L{string}
+        @in version: query
+        @required version: True
+        @param project: project name
+        @type project: L{string}
+        @in project: query
+        @required project: True
+        @return 200: trust indicator is added.
+        @raise 404:  scenario/installer/version/project not existed
+        """
+        self.do_update('trust_indicators',
+                       'post',
+                       locators={'scenario': scenario,
+                                 'installer': None,
+                                 'version': None,
+                                 'project': None})
+
+
+class ScenarioCustomsHandler(GenericScenarioUpdateHandler):
+    @swagger.operation(nickname="addCustomizedTestCases")
+    def post(self, scenario):
+        """
+        @description: add customized test cases
+        @notes: add several test cases to a project
+            POST /api/v1/scenarios/<scenario_name>/customs? \
+                installer=<installer_name>& \
+                version=<version_name>& \
+                project=<project_name>
+        @param body: test cases to be added
+        @type body: C{list} of L{string}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @param version: version
+        @type version: L{string}
+        @in version: query
+        @required version: True
+        @param project: project name
+        @type project: L{string}
+        @in project: query
+        @required project: True
+        @return 200: test cases are added.
+        @raise 404:  scenario/installer/version/project not existed
+        """
+        self.do_update('customs',
+                       'post',
+                       locators={'scenario': scenario,
+                                 'installer': None,
+                                 'version': None,
+                                 'project': None})
+
+    @swagger.operation(nickname="updateCustomizedTestCases")
+    def put(self, scenario):
+        """
+        @description: update customized test cases
+        @notes: substitute all the customized test cases
+            PUT /api/v1/scenarios/<scenario_name>/customs? \
+                installer=<installer_name>& \
+                version=<version_name>& \
+                project=<project_name>
+        @param body: new supported test cases
+        @type body: C{list} of L{string}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @param version: version
+        @type version: L{string}
+        @in version: query
+        @required version: True
+        @param project: project name
+        @type project: L{string}
+        @in project: query
+        @required project: True
+        @return 200: substitute test cases success.
+        @raise 404:  scenario/installer/version/project not existed
+        """
+        self.do_update('customs',
+                       'put',
+                       locators={'scenario': scenario,
+                                 'installer': None,
+                                 'version': None,
+                                 'project': None})
+
+    @swagger.operation(nickname="deleteCustomizedTestCases")
+    def delete(self, scenario):
+        """
+        @description: delete one or several customized test cases
+        @notes: delete one or some customized test cases
+            DELETE /api/v1/scenarios/<scenario_name>/customs? \
+                installer=<installer_name>& \
+                version=<version_name>& \
+                project=<project_name>
+        @param body: test case(s) to be deleted
+        @type body: C{list} of L{string}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @param version: version
+        @type version: L{string}
+        @in version: query
+        @required version: True
+        @param project: project name
+        @type project: L{string}
+        @in project: query
+        @required project: True
+        @return 200: delete test case(s) success.
+        @raise 404:  scenario/installer/version/project not existed
+        """
+        self.do_update('customs',
+                       'delete',
+                       locators={'scenario': scenario,
+                                 'installer': None,
+                                 'version': None,
+                                 'project': None})
 
-    @property
-    def _op(self):
-        return self.json_args.get('op')
 
-    @property
-    def _locate(self):
-        return self.json_args.get('locate')
+class ScenarioProjectsHandler(GenericScenarioUpdateHandler):
+    @swagger.operation(nickname="addProjectsUnderScenario")
+    def post(self, scenario):
+        """
+        @description: add projects to scenario
+        @notes: add one or multiple projects
+            POST /api/v1/scenarios/<scenario_name>/projects? \
+                installer=<installer_name>& \
+                version=<version_name>
+        @param body: projects to be added
+        @type body: C{list} of L{ScenarioProject}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @param version: version
+        @type version: L{string}
+        @in version: query
+        @required version: True
+        @return 200: projects are added.
+        @raise 400: bad schema
+        @raise 409: conflict, project already exists
+        @raise 404:  scenario/installer/version not existed
+        """
+        self.do_update('projects',
+                       'post',
+                       locators={'scenario': scenario,
+                                 'installer': None,
+                                 'version': None})
+
+    @swagger.operation(nickname="updateScenarioProjects")
+    def put(self, scenario):
+        """
+        @description: replace all projects
+        @notes: substitute all projects, delete existed ones with new provides
+            PUT /api/v1/scenarios/<scenario_name>/projects? \
+                installer=<installer_name>& \
+                version=<version_name>
+        @param body: new projects
+        @type body: C{list} of L{ScenarioProject}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @param version: version
+        @type version: L{string}
+        @in version: query
+        @required version: True
+        @return 200: replace projects success.
+        @raise 400: bad schema
+        @raise 404:  scenario/installer/version not existed
+        """
+        self.do_update('projects',
+                       'put',
+                       locators={'scenario': scenario,
+                                 'installer': None,
+                                 'version': None})
+
+    @swagger.operation(nickname="deleteProjectsUnderScenario")
+    def delete(self, scenario):
+        """
+        @description: delete one or multiple projects
+        @notes: delete one or multiple projects
+            DELETE /api/v1/scenarios/<scenario_name>/projects? \
+                installer=<installer_name>& \
+                version=<version_name>
+        @param body: projects(names) to be deleted
+        @type body: C{list} of L{string}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @param version: version
+        @type version: L{string}
+        @in version: query
+        @required version: True
+        @return 200: delete project(s) success.
+        @raise 404:  scenario/installer/version not existed
+        """
+        self.do_update('projects',
+                       'delete',
+                       locators={'scenario': scenario,
+                                 'installer': None,
+                                 'version': None})
 
-    @property
-    def _term(self):
-        return self.json_args.get('term')
+
+class ScenarioOwnerHandler(GenericScenarioUpdateHandler):
+    @swagger.operation(nickname="changeScenarioOwner")
+    def put(self, scenario):
+        """
+        @description: change scenario owner
+        @notes: substitute all projects, delete existed ones with new provides
+            PUT /api/v1/scenarios/<scenario_name>/owner? \
+                installer=<installer_name>& \
+                version=<version_name>
+        @param body: new owner
+        @type body: L{ScenarioChangeOwnerRequest}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @param version: version
+        @type version: L{string}
+        @in version: query
+        @required version: True
+        @return 200: change owner success.
+        @raise 404:  scenario/installer/version not existed
+        """
+        self.do_update('owner',
+                       'put',
+                       locators={'scenario': scenario,
+                                 'installer': None,
+                                 'version': None})
+
+
+class ScenarioVersionsHandler(GenericScenarioUpdateHandler):
+    @swagger.operation(nickname="addVersionsUnderScenario")
+    def post(self, scenario):
+        """
+        @description: add versions to scenario
+        @notes: add one or multiple versions
+            POST /api/v1/scenarios/<scenario_name>/versions? \
+                installer=<installer_name>
+        @param body: versions to be added
+        @type body: C{list} of L{ScenarioVersion}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @return 200: versions are added.
+        @raise 400: bad schema
+        @raise 409: conflict, version already exists
+        @raise 404:  scenario/installer not exist
+        """
+        self.do_update('versions',
+                       'post',
+                       locators={'scenario': scenario,
+                                 'installer': None})
+
+    @swagger.operation(nickname="updateVersionsUnderScenario")
+    def put(self, scenario):
+        """
+        @description: replace all versions
+        @notes: substitute all versions as a totality
+            PUT /api/v1/scenarios/<scenario_name>/versions? \
+                installer=<installer_name>
+        @param body: new versions
+        @type body: C{list} of L{ScenarioVersion}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @return 200: replace versions success.
+        @raise 400: bad schema
+        @raise 404:  scenario/installer not exist
+        """
+        self.do_update('versions',
+                       'put',
+                       locators={'scenario': scenario,
+                                 'installer': None})
+
+    @swagger.operation(nickname="deleteVersionsUnderScenario")
+    def delete(self, scenario):
+        """
+        @description: delete one or multiple versions
+        @notes: delete one or multiple versions
+            DELETE /api/v1/scenarios/<scenario_name>/versions? \
+                installer=<installer_name>
+        @param body: versions(names) to be deleted
+        @type body: C{list} of L{string}
+        @in body: body
+        @param installer: installer type
+        @type installer: L{string}
+        @in installer: query
+        @required installer: True
+        @return 200: delete versions success.
+        @raise 404:  scenario/installer not exist
+        """
+        self.do_update('versions',
+                       'delete',
+                       locators={'scenario': scenario,
+                                 'installer': None})
+
+
+class ScenarioInstallersHandler(GenericScenarioUpdateHandler):
+    @swagger.operation(nickname="addInstallersUnderScenario")
+    def post(self, scenario):
+        """
+        @description: add installers to scenario
+        @notes: add one or multiple installers
+            POST /api/v1/scenarios/<scenario_name>/installers
+        @param body: installers to be added
+        @type body: C{list} of L{ScenarioInstaller}
+        @in body: body
+        @return 200: installers are added.
+        @raise 400: bad schema
+        @raise 409: conflict, installer already exists
+        @raise 404:  scenario not exist
+        """
+        self.do_update('installers',
+                       'post',
+                       locators={'scenario': scenario})
+
+    @swagger.operation(nickname="updateInstallersUnderScenario")
+    def put(self, scenario):
+        """
+        @description: replace all installers
+        @notes: substitute all installers as a totality
+            PUT /api/v1/scenarios/<scenario_name>/installers
+        @param body: new installers
+        @type body: C{list} of L{ScenarioInstaller}
+        @in body: body
+        @return 200: replace versions success.
+        @raise 400: bad schema
+        @raise 404:  scenario/installer not exist
+        """
+        self.do_update('installers',
+                       'put',
+                       locators={'scenario': scenario})
+
+    @swagger.operation(nickname="deleteInstallersUnderScenario")
+    def delete(self, scenario):
+        """
+        @description: delete one or multiple installers
+        @notes: delete one or multiple installers
+            DELETE /api/v1/scenarios/<scenario_name>/installers
+        @param body: installers(names) to be deleted
+        @type body: C{list} of L{string}
+        @in body: body
+        @return 200: delete versions success.
+        @raise 404:  scenario/installer not exist
+        """
+        self.do_update('installers',
+                       'delete',
+                       locators={'scenario': scenario})
index 467cff2..d950ed1 100644 (file)
@@ -16,6 +16,13 @@ class ScenarioTI(models.ModelBase):
         self.date = date
         self.status = status
 
+    def __eq__(self, other):
+        return (self.date == other.date and
+                self.status == other.status)
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
 
 @swagger.model()
 class ScenarioScore(models.ModelBase):
@@ -23,6 +30,13 @@ class ScenarioScore(models.ModelBase):
         self.date = date
         self.score = score
 
+    def __eq__(self, other):
+        return (self.date == other.date and
+                self.score == other.score)
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
 
 @swagger.model()
 class ScenarioProject(models.ModelBase):
@@ -50,10 +64,10 @@ class ScenarioProject(models.ModelBase):
                 'trust_indicators': ScenarioTI}
 
     def __eq__(self, other):
-        return [self.project == other.project and
+        return (self.project == other.project and
                 self._customs_eq(other) and
                 self._scores_eq(other) and
-                self._ti_eq(other)]
+                self._ti_eq(other))
 
     def __ne__(self, other):
         return not self.__eq__(other)
@@ -62,10 +76,10 @@ class ScenarioProject(models.ModelBase):
         return set(self.customs) == set(other.customs)
 
     def _scores_eq(self, other):
-        return set(self.scores) == set(other.scores)
+        return self.scores == other.scores
 
     def _ti_eq(self, other):
-        return set(self.trust_indicators) == set(other.trust_indicators)
+        return self.trust_indicators == other.trust_indicators
 
 
 @swagger.model()
@@ -74,7 +88,8 @@ class ScenarioVersion(models.ModelBase):
         @property projects:
         @ptype projects: C{list} of L{ScenarioProject}
     """
-    def __init__(self, version=None, projects=None):
+    def __init__(self, owner=None, version=None, projects=None):
+        self.owner = owner
         self.version = version
         self.projects = list_default(projects)
 
@@ -83,7 +98,9 @@ class ScenarioVersion(models.ModelBase):
         return {'projects': ScenarioProject}
 
     def __eq__(self, other):
-        return [self.version == other.version and self._projects_eq(other)]
+        return (self.version == other.version and
+                self.owner == other.owner and
+                self._projects_eq(other))
 
     def __ne__(self, other):
         return not self.__eq__(other)
@@ -113,7 +130,7 @@ class ScenarioInstaller(models.ModelBase):
         return {'versions': ScenarioVersion}
 
     def __eq__(self, other):
-        return [self.installer == other.installer and self._versions_eq(other)]
+        return (self.installer == other.installer and self._versions_eq(other))
 
     def __ne__(self, other):
         return not self.__eq__(other)
@@ -143,19 +160,16 @@ class ScenarioCreateRequest(models.ModelBase):
         return {'installers': ScenarioInstaller}
 
 
+@swagger.model()
+class ScenarioChangeOwnerRequest(models.ModelBase):
+    def __init__(self, owner=None):
+        self.owner = owner
+
+
 @swagger.model()
 class ScenarioUpdateRequest(models.ModelBase):
-    """
-        @property field: update field
-        @property op: add/delete/update
-        @property locate: information used to locate the field
-        @property term: new value
-    """
-    def __init__(self, field=None, op=None, locate=None, term=None):
-        self.field = field
-        self.op = op
-        self.locate = dict_default(locate)
-        self.term = dict_default(term)
+    def __init__(self, name=None):
+        self.name = name
 
 
 @swagger.model()
@@ -178,7 +192,7 @@ class Scenario(models.ModelBase):
         return not self.__eq__(other)
 
     def __eq__(self, other):
-        return [self.name == other.name and self._installers_eq(other)]
+        return (self.name == other.name and self._installers_eq(other))
 
     def _installers_eq(self, other):
         for s_install in self.installers:
index a2312de..ce0a3ee 100644 (file)
@@ -8,7 +8,7 @@
 ##############################################################################
 import tornado.web
 
-from opnfv_testapi.common import config
+from opnfv_testapi.common.config import CONF
 from opnfv_testapi.resources import handlers
 from opnfv_testapi.resources import pod_handlers
 from opnfv_testapi.resources import project_handlers
@@ -48,20 +48,36 @@ mappings = [
     # Push results with mandatory request payload parameters
     # (project, case, and pod)
     (r"/api/v1/results", result_handlers.ResultsCLHandler),
+    (r'/api/v1/results/upload', result_handlers.ResultsUploadHandler),
     (r"/api/v1/results/([^/]+)", result_handlers.ResultsGURHandler),
 
     # scenarios
     (r"/api/v1/scenarios", scenario_handlers.ScenariosCLHandler),
     (r"/api/v1/scenarios/([^/]+)", scenario_handlers.ScenarioGURHandler),
+    (r"/api/v1/scenarios/([^/]+)/scores",
+     scenario_handlers.ScenarioScoresHandler),
+    (r"/api/v1/scenarios/([^/]+)/trust_indicators",
+     scenario_handlers.ScenarioTIsHandler),
+    (r"/api/v1/scenarios/([^/]+)/customs",
+     scenario_handlers.ScenarioCustomsHandler),
+    (r"/api/v1/scenarios/([^/]+)/projects",
+     scenario_handlers.ScenarioProjectsHandler),
+    (r"/api/v1/scenarios/([^/]+)/owner",
+     scenario_handlers.ScenarioOwnerHandler),
+    (r"/api/v1/scenarios/([^/]+)/versions",
+     scenario_handlers.ScenarioVersionsHandler),
+    (r"/api/v1/scenarios/([^/]+)/installers",
+     scenario_handlers.ScenarioInstallersHandler),
 
     # static path
     (r'/(.*\.(css|png|gif|js|html|json|map|woff2|woff|ttf))',
      tornado.web.StaticFileHandler,
-     {'path': config.Config().static_path}),
+     {'path': CONF.ui_static_path}),
 
     (r'/', root.RootHandler),
     (r'/api/v1/auth/signin', sign.SigninHandler),
-    (r'/api/v1/auth/signin_return', sign.SigninReturnHandler),
+    (r'/{}'.format(CONF.lfid_signin_return), sign.SigninReturnHandler),
     (r'/api/v1/auth/signout', sign.SignoutHandler),
-    (r'/api/v1/profile', user.ProfileHandler),
+    (r'/api/v1/profile', user.UserHandler),
+
 ]
diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/noparam.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/noparam.ini
deleted file mode 100644 (file)
index fda2a09..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# to add a new parameter in the config file,
-# the CONF object in config.ini must be updated
-[mongo]
-# URL of the mongo DB
-# Mongo auth url => mongodb://user1:pwd1@host1/?authSource=db1
-url = mongodb://127.0.0.1:27017/
-
-[api]
-# Listening port
-port = 8000
-# With debug_on set to true, error traces will be shown in HTTP responses
-debug = True
-authenticate = False
-
-[swagger]
-base_url = http://localhost:8000
diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/normal.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/normal.ini
deleted file mode 100644 (file)
index 77cc6c6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# to add a new parameter in the config file,
-# the CONF object in config.ini must be updated
-[mongo]
-# URL of the mongo DB
-# Mongo auth url => mongodb://user1:pwd1@host1/?authSource=db1
-url = mongodb://127.0.0.1:27017/
-dbname = test_results_collection
-
-[api]
-# Listening port
-port = 8000
-# With debug_on set to true, error traces will be shown in HTTP responses
-debug = True
-authenticate = False
-
-[swagger]
-base_url = http://localhost:8000
diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/nosection.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/nosection.ini
deleted file mode 100644 (file)
index 9988fc0..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# to add a new parameter in the config file,
-# the CONF object in config.ini must be updated
-[api]
-# Listening port
-port = 8000
-# With debug_on set to true, error traces will be shown in HTTP responses
-debug = True
-authenticate = False
-
-[swagger]
-base_url = http://localhost:8000
diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/notboolean.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/notboolean.ini
deleted file mode 100644 (file)
index b3f3276..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# to add a new parameter in the config file,
-# the CONF object in config.ini must be updated
-[mongo]
-# URL of the mongo DB
-# Mongo auth url => mongodb://user1:pwd1@host1/?authSource=db1
-url = mongodb://127.0.0.1:27017/
-dbname = test_results_collection
-
-[api]
-# Listening port
-port = 8000
-# With debug_on set to true, error traces will be shown in HTTP responses
-debug = True
-authenticate = notboolean
-
-[swagger]
-base_url = http://localhost:8000
diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/notint.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/notint.ini
deleted file mode 100644 (file)
index d1b752a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# to add a new parameter in the config file,
-# the CONF object in config.ini must be updated
-[mongo]
-# URL of the mongo DB
-# Mongo auth url => mongodb://user1:pwd1@host1/?authSource=db1
-url = mongodb://127.0.0.1:27017/
-dbname = test_results_collection
-
-[api]
-# Listening port
-port = notint
-# With debug_on set to true, error traces will be shown in HTTP responses
-debug = True
-authenticate = False
-
-[swagger]
-base_url = http://localhost:8000
index 446b944..8cfc513 100644 (file)
@@ -1,16 +1,15 @@
-import os
+import argparse
 
-from opnfv_testapi.common import config
 
-
-def test_config_success():
-    config_file = os.path.join(os.path.dirname(__file__),
-                               '../../../../etc/config.ini')
-    config.Config.CONFIG = config_file
-    conf = config.Config()
-    assert conf.mongo_url == 'mongodb://127.0.0.1:27017/'
-    assert conf.mongo_dbname == 'test_results_collection'
-    assert conf.api_port == 8000
-    assert conf.api_debug is True
-    assert conf.api_authenticate is False
-    assert conf.swagger_base_url == 'http://localhost:8000'
+def test_config_normal(mocker, config_normal):
+    mocker.patch(
+        'argparse.ArgumentParser.parse_known_args',
+        return_value=(argparse.Namespace(config_file=config_normal), None))
+    from opnfv_testapi.common import config
+    CONF = config.Config()
+    assert CONF.mongo_url == 'mongodb://127.0.0.1:27017/'
+    assert CONF.mongo_dbname == 'test_results_collection'
+    assert CONF.api_port == 8000
+    assert CONF.api_debug is True
+    assert CONF.api_authenticate is False
+    assert CONF.ui_url == 'http://localhost:8000'
diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/conftest.py b/utils/test/testapi/opnfv_testapi/tests/unit/conftest.py
new file mode 100644 (file)
index 0000000..75e621d
--- /dev/null
@@ -0,0 +1,8 @@
+from os import path
+
+import pytest
+
+
+@pytest.fixture
+def config_normal():
+    return path.join(path.dirname(__file__), '../../../etc/config.ini')
index b30c325..b8f696c 100644 (file)
@@ -10,6 +10,20 @@ import functools
 import httplib
 
 
+def upload(excepted_status, excepted_response):
+    def _upload(create_request):
+        @functools.wraps(create_request)
+        def wrap(self):
+            request = create_request(self)
+            status, body = self.upload(request)
+            if excepted_status == httplib.OK:
+                getattr(self, excepted_response)(body)
+            else:
+                self.assertIn(excepted_response, body)
+        return wrap
+    return _upload
+
+
 def create(excepted_status, excepted_response):
     def _create(create_request):
         @functools.wraps(create_request)
index adaf6f7..0ca83df 100644 (file)
@@ -6,9 +6,10 @@
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
+from operator import itemgetter
+
 from bson.objectid import ObjectId
 from concurrent.futures import ThreadPoolExecutor
-from operator import itemgetter
 
 
 def thread_execute(method, *args, **kwargs):
@@ -119,10 +120,14 @@ class MemDb(object):
 
     @staticmethod
     def _compare_date(spec, value):
+        gte = True
+        lt = False
         for k, v in spec.iteritems():
-            if k == '$gte' and value >= v:
-                return True
-        return False
+            if k == '$gte' and value < v:
+                gte = False
+            elif k == '$lt' and value < v:
+                lt = True
+        return gte and lt
 
     def _in(self, content, *args):
         if self.name == 'scenarios':
@@ -185,9 +190,8 @@ class MemDb(object):
                 elif k == 'trust_indicator.current':
                     if content.get('trust_indicator').get('current') != v:
                         return False
-                elif content.get(k, None) != v:
+                elif not isinstance(v, dict) and content.get(k, None) != v:
                     return False
-
         return True
 
     def _find(self, *args):
diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/resources/__init__.py b/utils/test/testapi/opnfv_testapi/tests/unit/resources/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
@@ -8,7 +8,7 @@
       [
         {
           "owner": "Lucky",
-          "version": "colorado",
+          "version": "danube",
           "projects":
           [
             {
@@ -29,7 +29,7 @@
               "scores": [
                 {
                   "date": "2017-01-08 22:46:44",
-                  "score": "0"
+                  "score": "0/1"
                 }
               ],
               "trust_indicators": [
@@ -12,13 +12,9 @@ from os import path
 import mock
 from tornado import testing
 
-from opnfv_testapi.common import config
 from opnfv_testapi.resources import models
 from opnfv_testapi.tests.unit import fake_pymongo
 
-config.Config.CONFIG = path.join(path.dirname(__file__),
-                                 '../../../etc/config.ini')
-
 
 class TestBase(testing.AsyncHTTPTestCase):
     headers = {'Content-Type': 'application/json; charset=UTF-8'}
@@ -37,21 +33,20 @@ class TestBase(testing.AsyncHTTPTestCase):
 
     def tearDown(self):
         self.db_patcher.stop()
+        self.config_patcher.stop()
 
     def _patch_server(self):
-        from opnfv_testapi.cmd import server
-        server.parse_config([
-            '--config-file',
-            path.join(path.dirname(__file__), 'common/normal.ini')
-        ])
-        self.db_patcher = mock.patch('opnfv_testapi.cmd.server.get_db',
-                                     self._fake_pymongo)
+        import argparse
+        config = path.join(path.dirname(__file__),
+                           '../../../../etc/config.ini')
+        self.config_patcher = mock.patch(
+            'argparse.ArgumentParser.parse_known_args',
+            return_value=(argparse.Namespace(config_file=config), None))
+        self.db_patcher = mock.patch('opnfv_testapi.db.api.DB',
+                                     fake_pymongo)
+        self.config_patcher.start()
         self.db_patcher.start()
 
-    @staticmethod
-    def _fake_pymongo():
-        return fake_pymongo
-
     def get_app(self):
         from opnfv_testapi.cmd import server
         return server.make_app()
@@ -66,9 +61,12 @@ class TestBase(testing.AsyncHTTPTestCase):
         return self.create_help(self.basePath, req, *args)
 
     def create_help(self, uri, req, *args):
+        return self.post_direct_url(self._update_uri(uri, *args), req)
+
+    def post_direct_url(self, url, req):
         if req and not isinstance(req, str) and hasattr(req, 'format'):
             req = req.format()
-        res = self.fetch(self._update_uri(uri, *args),
+        res = self.fetch(url,
                          method='POST',
                          body=json.dumps(req),
                          headers=self.headers)
@@ -92,21 +90,35 @@ class TestBase(testing.AsyncHTTPTestCase):
                          headers=self.headers)
         return self._get_return(res, self.list_res)
 
-    def update(self, new=None, *args):
-        if new:
+    def update_direct_url(self, url, new=None):
+        if new and hasattr(new, 'format'):
             new = new.format()
-        res = self.fetch(self._get_uri(*args),
+        res = self.fetch(url,
                          method='PUT',
                          body=json.dumps(new),
                          headers=self.headers)
         return self._get_return(res, self.update_res)
 
-    def delete(self, *args):
-        res = self.fetch(self._get_uri(*args),
-                         method='DELETE',
-                         headers=self.headers)
+    def update(self, new=None, *args):
+        return self.update_direct_url(self._get_uri(*args), new)
+
+    def delete_direct_url(self, url, body):
+        if body:
+            res = self.fetch(url,
+                             method='DELETE',
+                             body=json.dumps(body),
+                             headers=self.headers,
+                             allow_nonstandard_methods=True)
+        else:
+            res = self.fetch(url,
+                             method='DELETE',
+                             headers=self.headers)
+
         return res.code, res.body
 
+    def delete(self, *args):
+        return self.delete_direct_url(self._get_uri(*args), None)
+
     @staticmethod
     def _get_valid_args(*args):
         new_args = tuple(['%s' % arg for arg in args if arg is not None])
@@ -132,7 +144,10 @@ class TestBase(testing.AsyncHTTPTestCase):
     def _get_return(self, res, cls):
         code = res.code
         body = res.body
-        return code, self._get_return_body(code, body, cls)
+        if body:
+            return code, self._get_return_body(code, body, cls)
+        else:
+            return code, None
 
     @staticmethod
     def _get_return_body(code, body, cls):
@@ -12,7 +12,7 @@ import unittest
 from opnfv_testapi.common import message
 from opnfv_testapi.resources import pod_models
 from opnfv_testapi.tests.unit import executor
-from opnfv_testapi.tests.unit import test_base as base
+from opnfv_testapi.tests.unit.resources import test_base as base
 
 
 class TestPodBase(base.TestBase):
@@ -85,5 +85,6 @@ class TestPodGet(TestPodBase):
             else:
                 self.assert_get_body(pod, self.req_e)
 
+
 if __name__ == '__main__':
     unittest.main()
@@ -4,7 +4,7 @@ import unittest
 from opnfv_testapi.common import message
 from opnfv_testapi.resources import project_models
 from opnfv_testapi.tests.unit import executor
-from opnfv_testapi.tests.unit import test_base as base
+from opnfv_testapi.tests.unit.resources import test_base as base
 
 
 class TestProjectBase(base.TestBase):
@@ -132,5 +132,6 @@ class TestProjectDelete(TestProjectBase):
         code, body = self.get(self.req_d.name)
         self.assertEqual(code, httplib.NOT_FOUND)
 
+
 if __name__ == '__main__':
     unittest.main()
@@ -7,17 +7,18 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 import copy
-from datetime import datetime, timedelta
 import httplib
 import unittest
+from datetime import datetime, timedelta
+import json
 
 from opnfv_testapi.common import message
 from opnfv_testapi.resources import pod_models
 from opnfv_testapi.resources import project_models
 from opnfv_testapi.resources import result_models
 from opnfv_testapi.resources import testcase_models
-from opnfv_testapi.tests.unit import test_base as base
 from opnfv_testapi.tests.unit import executor
+from opnfv_testapi.tests.unit.resources import test_base as base
 
 
 class Details(object):
@@ -60,9 +61,9 @@ class TestResultBase(base.TestBase):
         self.scenario = 'odl-l2'
         self.criteria = 'passed'
         self.trust_indicator = result_models.TI(0.7)
-        self.start_date = "2016-05-23 07:16:09.477097"
-        self.stop_date = "2016-05-23 07:16:19.477097"
-        self.update_date = "2016-05-24 07:16:19.477097"
+        self.start_date = str(datetime.now())
+        self.stop_date = str(datetime.now() + timedelta(minutes=1))
+        self.update_date = str(datetime.now() + timedelta(days=1))
         self.update_step = -0.05
         super(TestResultBase, self).setUp()
         self.details = Details(timestart='0', duration='9s', status='OK')
@@ -131,6 +132,22 @@ class TestResultBase(base.TestBase):
         _, res = self.create_d()
         return res.href.split('/')[-1]
 
+    def upload(self, req):
+        if req and not isinstance(req, str) and hasattr(req, 'format'):
+            req = req.format()
+        res = self.fetch(self.basePath + '/upload',
+                         method='POST',
+                         body=json.dumps(req),
+                         headers=self.headers)
+
+        return self._get_return(res, self.create_res)
+
+
+class TestResultUpload(TestResultBase):
+    @executor.upload(httplib.BAD_REQUEST, message.key_error('file'))
+    def test_filenotfind(self):
+        return None
+
 
 class TestResultCreate(TestResultBase):
     @executor.create(httplib.BAD_REQUEST, message.no_body())
@@ -208,9 +225,9 @@ class TestResultCreate(TestResultBase):
 class TestResultGet(TestResultBase):
     def setUp(self):
         super(TestResultGet, self).setUp()
+        self.req_10d_before = self._create_changed_date(days=-10)
         self.req_d_id = self._create_d()
         self.req_10d_later = self._create_changed_date(days=10)
-        self.req_10d_before = self._create_changed_date(days=-10)
 
     @executor.get(httplib.OK, 'assert_res')
     def test_getOne(self):
@@ -256,9 +273,9 @@ class TestResultGet(TestResultBase):
     def test_queryPeriodNotInt(self):
         return self._set_query('period=a')
 
-    @executor.query(httplib.OK, '_query_last_one', 1)
+    @executor.query(httplib.OK, '_query_period_one', 1)
     def test_queryPeriodSuccess(self):
-        return self._set_query('period=1')
+        return self._set_query('period=5')
 
     @executor.query(httplib.BAD_REQUEST, message.must_int('last'))
     def test_queryLastNotInt(self):
@@ -268,7 +285,17 @@ class TestResultGet(TestResultBase):
     def test_queryLast(self):
         return self._set_query('last=1')
 
-    @executor.query(httplib.OK, '_query_last_one', 1)
+    @executor.query(httplib.OK, '_query_success', 4)
+    def test_queryPublic(self):
+        self._create_public_data()
+        return self._set_query('')
+
+    @executor.query(httplib.OK, '_query_success', 1)
+    def test_queryPrivate(self):
+        self._create_private_data()
+        return self._set_query('public=false')
+
+    @executor.query(httplib.OK, '_query_period_one', 1)
     def test_combination(self):
         return self._set_query('pod',
                                'project',
@@ -279,7 +306,7 @@ class TestResultGet(TestResultBase):
                                'scenario',
                                'trust_indicator',
                                'criteria',
-                               'period=1')
+                               'period=5')
 
     @executor.query(httplib.OK, '_query_success', 0)
     def test_notFound(self):
@@ -294,6 +321,14 @@ class TestResultGet(TestResultBase):
                                'criteria',
                                'period=1')
 
+    @executor.query(httplib.OK, '_query_success', 1)
+    def test_filterErrorStartdate(self):
+        self._create_error_start_date(None)
+        self._create_error_start_date('None')
+        self._create_error_start_date('null')
+        self._create_error_start_date('')
+        return self._set_query('period=5')
+
     def _query_success(self, body, number):
         self.assertEqual(number, len(body.results))
 
@@ -301,6 +336,16 @@ class TestResultGet(TestResultBase):
         self.assertEqual(number, len(body.results))
         self.assert_res(body.results[0], self.req_10d_later)
 
+    def _query_period_one(self, body, number):
+        self.assertEqual(number, len(body.results))
+        self.assert_res(body.results[0], self.req_d)
+
+    def _create_error_start_date(self, start_date):
+        req = copy.deepcopy(self.req_d)
+        req.start_date = start_date
+        self.create(req)
+        return req
+
     def _create_changed_date(self, **kwargs):
         req = copy.deepcopy(self.req_d)
         req.start_date = datetime.now() + timedelta(**kwargs)
@@ -309,16 +354,29 @@ class TestResultGet(TestResultBase):
         self.create(req)
         return req
 
+    def _create_public_data(self, **kwargs):
+        req = copy.deepcopy(self.req_d)
+        req.public = 'true'
+        self.create(req)
+        return req
+
+    def _create_private_data(self, **kwargs):
+        req = copy.deepcopy(self.req_d)
+        req.public = 'false'
+        self.create(req)
+        return req
+
     def _set_query(self, *args):
         def get_value(arg):
             return self.__getattribute__(arg) \
                 if arg != 'trust_indicator' else self.trust_indicator.current
         uri = ''
         for arg in args:
-            if '=' in arg:
-                uri += arg + '&'
-            else:
-                uri += '{}={}&'.format(arg, get_value(arg))
+            if arg:
+                if '=' in arg:
+                    uri += arg + '&'
+                else:
+                    uri += '{}={}&'.format(arg, get_value(arg))
         return uri[0: -1]
 
 
diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/resources/test_scenario.py b/utils/test/testapi/opnfv_testapi/tests/unit/resources/test_scenario.py
new file mode 100644 (file)
index 0000000..1367fc6
--- /dev/null
@@ -0,0 +1,449 @@
+import functools
+import httplib
+import json
+import os
+
+from datetime import datetime
+
+from opnfv_testapi.common import message
+import opnfv_testapi.resources.scenario_models as models
+from opnfv_testapi.tests.unit.resources import test_base as base
+
+
+def _none_default(check, default):
+    return check if check else default
+
+
+class TestScenarioBase(base.TestBase):
+    def setUp(self):
+        super(TestScenarioBase, self).setUp()
+        self.get_res = models.Scenario
+        self.list_res = models.Scenarios
+        self.basePath = '/api/v1/scenarios'
+        self.req_d = self._load_request('scenario-c1.json')
+        self.req_2 = self._load_request('scenario-c2.json')
+
+    def tearDown(self):
+        pass
+
+    def assert_body(self, project, req=None):
+        pass
+
+    @staticmethod
+    def _load_request(f_req):
+        abs_file = os.path.join(os.path.dirname(__file__), f_req)
+        with open(abs_file, 'r') as f:
+            loader = json.load(f)
+            f.close()
+        return loader
+
+    def create_return_name(self, req):
+        _, res = self.create(req)
+        return res.href.split('/')[-1]
+
+    def assert_res(self, code, scenario, req=None):
+        self.assertEqual(code, httplib.OK)
+        if req is None:
+            req = self.req_d
+        self.assertIsNotNone(scenario._id)
+        self.assertIsNotNone(scenario.creation_date)
+        self.assertEqual(scenario, models.Scenario.from_dict(req))
+
+    @staticmethod
+    def set_query(*args):
+        uri = ''
+        for arg in args:
+            uri += arg + '&'
+        return uri[0: -1]
+
+    def get_and_assert(self, name):
+        code, body = self.get(name)
+        self.assert_res(code, body, self.req_d)
+
+
+class TestScenarioCreate(TestScenarioBase):
+    def test_withoutBody(self):
+        (code, body) = self.create()
+        self.assertEqual(code, httplib.BAD_REQUEST)
+
+    def test_emptyName(self):
+        req_empty = models.ScenarioCreateRequest('')
+        (code, body) = self.create(req_empty)
+        self.assertEqual(code, httplib.BAD_REQUEST)
+        self.assertIn(message.missing('name'), body)
+
+    def test_noneName(self):
+        req_none = models.ScenarioCreateRequest(None)
+        (code, body) = self.create(req_none)
+        self.assertEqual(code, httplib.BAD_REQUEST)
+        self.assertIn(message.missing('name'), body)
+
+    def test_success(self):
+        (code, body) = self.create_d()
+        self.assertEqual(code, httplib.OK)
+        self.assert_create_body(body)
+
+    def test_alreadyExist(self):
+        self.create_d()
+        (code, body) = self.create_d()
+        self.assertEqual(code, httplib.FORBIDDEN)
+        self.assertIn(message.exist_base, body)
+
+
+class TestScenarioGet(TestScenarioBase):
+    def setUp(self):
+        super(TestScenarioGet, self).setUp()
+        self.scenario_1 = self.create_return_name(self.req_d)
+        self.scenario_2 = self.create_return_name(self.req_2)
+
+    def test_getByName(self):
+        self.get_and_assert(self.scenario_1)
+
+    def test_getAll(self):
+        self._query_and_assert(query=None, reqs=[self.req_d, self.req_2])
+
+    def test_queryName(self):
+        query = self.set_query('name=nosdn-nofeature-ha')
+        self._query_and_assert(query, reqs=[self.req_d])
+
+    def test_queryInstaller(self):
+        query = self.set_query('installer=apex')
+        self._query_and_assert(query, reqs=[self.req_d])
+
+    def test_queryVersion(self):
+        query = self.set_query('version=master')
+        self._query_and_assert(query, reqs=[self.req_d])
+
+    def test_queryProject(self):
+        query = self.set_query('project=functest')
+        self._query_and_assert(query, reqs=[self.req_d, self.req_2])
+
+    # close due to random fail, open again after solve it in another patch
+    # def test_queryCombination(self):
+    #     query = self._set_query('name=nosdn-nofeature-ha',
+    #                             'installer=apex',
+    #                             'version=master',
+    #                             'project=functest')
+    #
+    #     self._query_and_assert(query, reqs=[self.req_d])
+
+    def _query_and_assert(self, query, found=True, reqs=None):
+        code, body = self.query(query)
+        if not found:
+            self.assertEqual(code, httplib.OK)
+            self.assertEqual(0, len(body.scenarios))
+        else:
+            self.assertEqual(len(reqs), len(body.scenarios))
+            for req in reqs:
+                for scenario in body.scenarios:
+                    if req['name'] == scenario.name:
+                        self.assert_res(code, scenario, req)
+
+
+class TestScenarioDelete(TestScenarioBase):
+    def test_notFound(self):
+        code, body = self.delete('notFound')
+        self.assertEqual(code, httplib.NOT_FOUND)
+
+    def test_success(self):
+        scenario = self.create_return_name(self.req_d)
+        code, _ = self.delete(scenario)
+        self.assertEqual(code, httplib.OK)
+        code, _ = self.get(scenario)
+        self.assertEqual(code, httplib.NOT_FOUND)
+
+
+class TestScenarioUpdate(TestScenarioBase):
+    def setUp(self):
+        super(TestScenarioUpdate, self).setUp()
+        self.scenario = self.create_return_name(self.req_d)
+        self.scenario_2 = self.create_return_name(self.req_2)
+        self.update_url = ''
+        self.scenario_url = '/api/v1/scenarios/{}'.format(self.scenario)
+        self.installer = self.req_d['installers'][0]['installer']
+        self.version = self.req_d['installers'][0]['versions'][0]['version']
+        self.locate_project = 'installer={}&version={}&project={}'.format(
+            self.installer,
+            self.version,
+            'functest')
+
+    def update_url_fixture(item):
+        def _update_url_fixture(xstep):
+            def wrapper(self, *args, **kwargs):
+                self.update_url = '{}/{}'.format(self.scenario_url, item)
+                locator = None
+                if item in ['projects', 'owner']:
+                    locator = 'installer={}&version={}'.format(
+                        self.installer,
+                        self.version)
+                elif item in ['versions']:
+                    locator = 'installer={}'.format(
+                        self.installer)
+                elif item in ['rename']:
+                    self.update_url = self.scenario_url
+
+                if locator:
+                    self.update_url = '{}?{}'.format(self.update_url, locator)
+
+                xstep(self, *args, **kwargs)
+            return wrapper
+        return _update_url_fixture
+
+    def update_partial(operate, expected):
+        def _update_partial(set_update):
+            @functools.wraps(set_update)
+            def wrapper(self):
+                update = set_update(self)
+                code, body = getattr(self, operate)(update)
+                getattr(self, expected)(code)
+            return wrapper
+        return _update_partial
+
+    @update_partial('_add', '_success')
+    def test_addScore(self):
+        add = models.ScenarioScore(date=str(datetime.now()), score='11/12')
+        projects = self.req_d['installers'][0]['versions'][0]['projects']
+        functest = filter(lambda f: f['project'] == 'functest', projects)[0]
+        functest['scores'].append(add.format())
+        self.update_url = '{}/scores?{}'.format(self.scenario_url,
+                                                self.locate_project)
+
+        return add
+
+    @update_partial('_add', '_success')
+    def test_addTrustIndicator(self):
+        add = models.ScenarioTI(date=str(datetime.now()), status='gold')
+        projects = self.req_d['installers'][0]['versions'][0]['projects']
+        functest = filter(lambda f: f['project'] == 'functest', projects)[0]
+        functest['trust_indicators'].append(add.format())
+        self.update_url = '{}/trust_indicators?{}'.format(self.scenario_url,
+                                                          self.locate_project)
+
+        return add
+
+    @update_partial('_add', '_success')
+    def test_addCustoms(self):
+        adds = ['odl', 'parser', 'vping_ssh']
+        projects = self.req_d['installers'][0]['versions'][0]['projects']
+        functest = filter(lambda f: f['project'] == 'functest', projects)[0]
+        functest['customs'] = list(set(functest['customs'] + adds))
+        self.update_url = '{}/customs?{}'.format(self.scenario_url,
+                                                 self.locate_project)
+        return adds
+
+    @update_partial('_update', '_success')
+    def test_updateCustoms(self):
+        updates = ['odl', 'parser', 'vping_ssh']
+        projects = self.req_d['installers'][0]['versions'][0]['projects']
+        functest = filter(lambda f: f['project'] == 'functest', projects)[0]
+        functest['customs'] = updates
+        self.update_url = '{}/customs?{}'.format(self.scenario_url,
+                                                 self.locate_project)
+
+        return updates
+
+    @update_partial('_delete', '_success')
+    def test_deleteCustoms(self):
+        deletes = ['vping_ssh']
+        projects = self.req_d['installers'][0]['versions'][0]['projects']
+        functest = filter(lambda f: f['project'] == 'functest', projects)[0]
+        functest['customs'] = ['healthcheck']
+        self.update_url = '{}/customs?{}'.format(self.scenario_url,
+                                                 self.locate_project)
+
+        return deletes
+
+    @update_url_fixture('projects')
+    @update_partial('_add', '_success')
+    def test_addProjects_succ(self):
+        add = models.ScenarioProject(project='qtip').format()
+        self.req_d['installers'][0]['versions'][0]['projects'].append(add)
+        return [add]
+
+    @update_url_fixture('projects')
+    @update_partial('_add', '_conflict')
+    def test_addProjects_already_exist(self):
+        add = models.ScenarioProject(project='functest').format()
+        return [add]
+
+    @update_url_fixture('projects')
+    @update_partial('_add', '_bad_request')
+    def test_addProjects_bad_schema(self):
+        add = models.ScenarioProject(project='functest').format()
+        add['score'] = None
+        return [add]
+
+    @update_url_fixture('projects')
+    @update_partial('_update', '_success')
+    def test_updateProjects_succ(self):
+        update = models.ScenarioProject(project='qtip').format()
+        self.req_d['installers'][0]['versions'][0]['projects'] = [update]
+        return [update]
+
+    @update_url_fixture('projects')
+    @update_partial('_update', '_conflict')
+    def test_updateProjects_duplicated(self):
+        update = models.ScenarioProject(project='qtip').format()
+        return [update, update]
+
+    @update_url_fixture('projects')
+    @update_partial('_update', '_bad_request')
+    def test_updateProjects_bad_schema(self):
+        update = models.ScenarioProject(project='functest').format()
+        update['score'] = None
+        return [update]
+
+    @update_url_fixture('projects')
+    @update_partial('_delete', '_success')
+    def test_deleteProjects(self):
+        deletes = ['functest']
+        projects = self.req_d['installers'][0]['versions'][0]['projects']
+        self.req_d['installers'][0]['versions'][0]['projects'] = filter(
+            lambda f: f['project'] != 'functest',
+            projects)
+        return deletes
+
+    @update_url_fixture('owner')
+    @update_partial('_update', '_success')
+    def test_changeOwner(self):
+        new_owner = 'new_owner'
+        update = models.ScenarioChangeOwnerRequest(new_owner).format()
+        self.req_d['installers'][0]['versions'][0]['owner'] = new_owner
+        return update
+
+    @update_url_fixture('versions')
+    @update_partial('_add', '_success')
+    def test_addVersions_succ(self):
+        add = models.ScenarioVersion(version='Euphrates').format()
+        self.req_d['installers'][0]['versions'].append(add)
+        return [add]
+
+    @update_url_fixture('versions')
+    @update_partial('_add', '_conflict')
+    def test_addVersions_already_exist(self):
+        add = models.ScenarioVersion(version='master').format()
+        return [add]
+
+    @update_url_fixture('versions')
+    @update_partial('_add', '_bad_request')
+    def test_addVersions_bad_schema(self):
+        add = models.ScenarioVersion(version='euphrates').format()
+        add['notexist'] = None
+        return [add]
+
+    @update_url_fixture('versions')
+    @update_partial('_update', '_success')
+    def test_updateVersions_succ(self):
+        update = models.ScenarioVersion(version='euphrates').format()
+        self.req_d['installers'][0]['versions'] = [update]
+        return [update]
+
+    @update_url_fixture('versions')
+    @update_partial('_update', '_conflict')
+    def test_updateVersions_duplicated(self):
+        update = models.ScenarioVersion(version='euphrates').format()
+        return [update, update]
+
+    @update_url_fixture('versions')
+    @update_partial('_update', '_bad_request')
+    def test_updateVersions_bad_schema(self):
+        update = models.ScenarioVersion(version='euphrates').format()
+        update['not_owner'] = 'Iam'
+        return [update]
+
+    @update_url_fixture('versions')
+    @update_partial('_delete', '_success')
+    def test_deleteVersions(self):
+        deletes = ['master']
+        versions = self.req_d['installers'][0]['versions']
+        self.req_d['installers'][0]['versions'] = filter(
+            lambda f: f['version'] != 'master',
+            versions)
+        return deletes
+
+    @update_url_fixture('installers')
+    @update_partial('_add', '_success')
+    def test_addInstallers_succ(self):
+        add = models.ScenarioInstaller(installer='daisy').format()
+        self.req_d['installers'].append(add)
+        return [add]
+
+    @update_url_fixture('installers')
+    @update_partial('_add', '_conflict')
+    def test_addInstallers_already_exist(self):
+        add = models.ScenarioInstaller(installer='apex').format()
+        return [add]
+
+    @update_url_fixture('installers')
+    @update_partial('_add', '_bad_request')
+    def test_addInstallers_bad_schema(self):
+        add = models.ScenarioInstaller(installer='daisy').format()
+        add['not_exist'] = 'not_exist'
+        return [add]
+
+    @update_url_fixture('installers')
+    @update_partial('_update', '_success')
+    def test_updateInstallers_succ(self):
+        update = models.ScenarioInstaller(installer='daisy').format()
+        self.req_d['installers'] = [update]
+        return [update]
+
+    @update_url_fixture('installers')
+    @update_partial('_update', '_conflict')
+    def test_updateInstallers_duplicated(self):
+        update = models.ScenarioInstaller(installer='daisy').format()
+        return [update, update]
+
+    @update_url_fixture('installers')
+    @update_partial('_update', '_bad_request')
+    def test_updateInstallers_bad_schema(self):
+        update = models.ScenarioInstaller(installer='daisy').format()
+        update['not_exist'] = 'not_exist'
+        return [update]
+
+    @update_url_fixture('installers')
+    @update_partial('_delete', '_success')
+    def test_deleteInstallers(self):
+        deletes = ['apex']
+        installers = self.req_d['installers']
+        self.req_d['installers'] = filter(
+            lambda f: f['installer'] != 'apex',
+            installers)
+        return deletes
+
+    @update_url_fixture('rename')
+    @update_partial('_update', '_success')
+    def test_renameScenario(self):
+        new_name = 'new_scenario_name'
+        update = models.ScenarioUpdateRequest(name=new_name)
+        self.req_d['name'] = new_name
+        return update
+
+    @update_url_fixture('rename')
+    @update_partial('_update', '_forbidden')
+    def test_renameScenario_exist(self):
+        new_name = self.req_d['name']
+        update = models.ScenarioUpdateRequest(name=new_name)
+        return update
+
+    def _add(self, update_req):
+        return self.post_direct_url(self.update_url, update_req)
+
+    def _update(self, update_req):
+        return self.update_direct_url(self.update_url, update_req)
+
+    def _delete(self, update_req):
+        return self.delete_direct_url(self.update_url, update_req)
+
+    def _success(self, status):
+        self.assertEqual(status, httplib.OK)
+        self.get_and_assert(self.req_d['name'])
+
+    def _forbidden(self, status):
+        self.assertEqual(status, httplib.FORBIDDEN)
+
+    def _bad_request(self, status):
+        self.assertEqual(status, httplib.BAD_REQUEST)
+
+    def _conflict(self, status):
+        self.assertEqual(status, httplib.CONFLICT)
@@ -13,8 +13,8 @@ import unittest
 from opnfv_testapi.common import message
 from opnfv_testapi.resources import project_models
 from opnfv_testapi.resources import testcase_models
-from opnfv_testapi.tests.unit import test_base as base
 from opnfv_testapi.tests.unit import executor
+from opnfv_testapi.tests.unit.resources import test_base as base
 
 
 class TestCaseBase(base.TestBase):
@@ -10,14 +10,14 @@ from tornado import web
 
 from opnfv_testapi.common import message
 from opnfv_testapi.resources import project_models
-from opnfv_testapi.router import url_mappings
 from opnfv_testapi.tests.unit import executor
 from opnfv_testapi.tests.unit import fake_pymongo
-from opnfv_testapi.tests.unit import test_base as base
+from opnfv_testapi.tests.unit.resources import test_base as base
 
 
 class TestToken(base.TestBase):
     def get_app(self):
+        from opnfv_testapi.router import url_mappings
         return web.Application(
             url_mappings.mappings,
             db=fake_pymongo,
@@ -109,5 +109,6 @@ class TestTokenUpdateProject(TestToken):
     def _update_success(self, request, body):
         self.assertIn(request.name, body)
 
+
 if __name__ == '__main__':
     unittest.main()
@@ -11,7 +11,7 @@ import unittest
 
 from opnfv_testapi.resources import models
 from opnfv_testapi.tests.unit import executor
-from opnfv_testapi.tests.unit import test_base as base
+from opnfv_testapi.tests.unit.resources import test_base as base
 
 
 class TestVersionBase(base.TestBase):
diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_scenario.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_scenario.py
deleted file mode 100644 (file)
index b232bc1..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-from copy import deepcopy
-from datetime import datetime
-import functools
-import httplib
-import json
-import os
-
-from opnfv_testapi.common import message
-import opnfv_testapi.resources.scenario_models as models
-from opnfv_testapi.tests.unit import test_base as base
-
-
-class TestScenarioBase(base.TestBase):
-    def setUp(self):
-        super(TestScenarioBase, self).setUp()
-        self.get_res = models.Scenario
-        self.list_res = models.Scenarios
-        self.basePath = '/api/v1/scenarios'
-        self.req_d = self._load_request('scenario-c1.json')
-        self.req_2 = self._load_request('scenario-c2.json')
-
-    def tearDown(self):
-        pass
-
-    def assert_body(self, project, req=None):
-        pass
-
-    @staticmethod
-    def _load_request(f_req):
-        abs_file = os.path.join(os.path.dirname(__file__), f_req)
-        with open(abs_file, 'r') as f:
-            loader = json.load(f)
-            f.close()
-        return loader
-
-    def create_return_name(self, req):
-        _, res = self.create(req)
-        return res.href.split('/')[-1]
-
-    def assert_res(self, code, scenario, req=None):
-        self.assertEqual(code, httplib.OK)
-        if req is None:
-            req = self.req_d
-        self.assertIsNotNone(scenario._id)
-        self.assertIsNotNone(scenario.creation_date)
-
-        scenario == models.Scenario.from_dict(req)
-
-    @staticmethod
-    def _set_query(*args):
-        uri = ''
-        for arg in args:
-            uri += arg + '&'
-        return uri[0: -1]
-
-    def _get_and_assert(self, name, req=None):
-        code, body = self.get(name)
-        self.assert_res(code, body, req)
-
-
-class TestScenarioCreate(TestScenarioBase):
-    def test_withoutBody(self):
-        (code, body) = self.create()
-        self.assertEqual(code, httplib.BAD_REQUEST)
-
-    def test_emptyName(self):
-        req_empty = models.ScenarioCreateRequest('')
-        (code, body) = self.create(req_empty)
-        self.assertEqual(code, httplib.BAD_REQUEST)
-        self.assertIn(message.missing('name'), body)
-
-    def test_noneName(self):
-        req_none = models.ScenarioCreateRequest(None)
-        (code, body) = self.create(req_none)
-        self.assertEqual(code, httplib.BAD_REQUEST)
-        self.assertIn(message.missing('name'), body)
-
-    def test_success(self):
-        (code, body) = self.create_d()
-        self.assertEqual(code, httplib.OK)
-        self.assert_create_body(body)
-
-    def test_alreadyExist(self):
-        self.create_d()
-        (code, body) = self.create_d()
-        self.assertEqual(code, httplib.FORBIDDEN)
-        self.assertIn(message.exist_base, body)
-
-
-class TestScenarioGet(TestScenarioBase):
-    def setUp(self):
-        super(TestScenarioGet, self).setUp()
-        self.scenario_1 = self.create_return_name(self.req_d)
-        self.scenario_2 = self.create_return_name(self.req_2)
-
-    def test_getByName(self):
-        self._get_and_assert(self.scenario_1, self.req_d)
-
-    def test_getAll(self):
-        self._query_and_assert(query=None, reqs=[self.req_d, self.req_2])
-
-    def test_queryName(self):
-        query = self._set_query('name=nosdn-nofeature-ha')
-        self._query_and_assert(query, reqs=[self.req_d])
-
-    def test_queryInstaller(self):
-        query = self._set_query('installer=apex')
-        self._query_and_assert(query, reqs=[self.req_d])
-
-    def test_queryVersion(self):
-        query = self._set_query('version=master')
-        self._query_and_assert(query, reqs=[self.req_d])
-
-    def test_queryProject(self):
-        query = self._set_query('project=functest')
-        self._query_and_assert(query, reqs=[self.req_d, self.req_2])
-
-    def test_queryCombination(self):
-        query = self._set_query('name=nosdn-nofeature-ha',
-                                'installer=apex',
-                                'version=master',
-                                'project=functest')
-
-        self._query_and_assert(query, reqs=[self.req_d])
-
-    def _query_and_assert(self, query, found=True, reqs=None):
-        code, body = self.query(query)
-        if not found:
-            self.assertEqual(code, httplib.OK)
-            self.assertEqual(0, len(body.scenarios))
-        else:
-            self.assertEqual(len(reqs), len(body.scenarios))
-            for req in reqs:
-                for scenario in body.scenarios:
-                    if req['name'] == scenario.name:
-                        self.assert_res(code, scenario, req)
-
-
-class TestScenarioUpdate(TestScenarioBase):
-    def setUp(self):
-        super(TestScenarioUpdate, self).setUp()
-        self.scenario = self.create_return_name(self.req_d)
-        self.scenario_2 = self.create_return_name(self.req_2)
-
-    def _execute(set_update):
-        @functools.wraps(set_update)
-        def magic(self):
-            update, scenario = set_update(self, deepcopy(self.req_d))
-            self._update_and_assert(update, scenario)
-        return magic
-
-    def _update(expected):
-        def _update(set_update):
-            @functools.wraps(set_update)
-            def wrap(self):
-                update, scenario = set_update(self, deepcopy(self.req_d))
-                code, body = self.update(update, self.scenario)
-                getattr(self, expected)(code, scenario)
-            return wrap
-        return _update
-
-    @_update('_success')
-    def test_renameScenario(self, scenario):
-        new_name = 'nosdn-nofeature-noha'
-        scenario['name'] = new_name
-        update_req = models.ScenarioUpdateRequest(field='name',
-                                                  op='update',
-                                                  locate={},
-                                                  term={'name': new_name})
-        return update_req, scenario
-
-    @_update('_forbidden')
-    def test_renameScenario_exist(self, scenario):
-        new_name = self.scenario_2
-        scenario['name'] = new_name
-        update_req = models.ScenarioUpdateRequest(field='name',
-                                                  op='update',
-                                                  locate={},
-                                                  term={'name': new_name})
-        return update_req, scenario
-
-    @_update('_bad_request')
-    def test_renameScenario_noName(self, scenario):
-        new_name = self.scenario_2
-        scenario['name'] = new_name
-        update_req = models.ScenarioUpdateRequest(field='name',
-                                                  op='update',
-                                                  locate={},
-                                                  term={})
-        return update_req, scenario
-
-    @_execute
-    def test_addInstaller(self, scenario):
-        add = models.ScenarioInstaller(installer='daisy', versions=list())
-        scenario['installers'].append(add.format())
-        update = models.ScenarioUpdateRequest(field='installer',
-                                              op='add',
-                                              locate={},
-                                              term=add.format())
-        return update, scenario
-
-    @_execute
-    def test_deleteInstaller(self, scenario):
-        scenario['installers'] = filter(lambda f: f['installer'] != 'apex',
-                                        scenario['installers'])
-
-        update = models.ScenarioUpdateRequest(field='installer',
-                                              op='delete',
-                                              locate={'installer': 'apex'})
-        return update, scenario
-
-    @_execute
-    def test_addVersion(self, scenario):
-        add = models.ScenarioVersion(version='danube', projects=list())
-        scenario['installers'][0]['versions'].append(add.format())
-        update = models.ScenarioUpdateRequest(field='version',
-                                              op='add',
-                                              locate={'installer': 'apex'},
-                                              term=add.format())
-        return update, scenario
-
-    @_execute
-    def test_deleteVersion(self, scenario):
-        scenario['installers'][0]['versions'] = filter(
-            lambda f: f['version'] != 'master',
-            scenario['installers'][0]['versions'])
-
-        update = models.ScenarioUpdateRequest(field='version',
-                                              op='delete',
-                                              locate={'installer': 'apex',
-                                                      'version': 'master'})
-        return update, scenario
-
-    @_execute
-    def test_changeOwner(self, scenario):
-        scenario['installers'][0]['versions'][0]['owner'] = 'lucy'
-
-        update = models.ScenarioUpdateRequest(field='owner',
-                                              op='update',
-                                              locate={'installer': 'apex',
-                                                      'version': 'master'},
-                                              term={'owner': 'lucy'})
-        return update, scenario
-
-    @_execute
-    def test_addProject(self, scenario):
-        add = models.ScenarioProject(project='qtip').format()
-        scenario['installers'][0]['versions'][0]['projects'].append(add)
-        update = models.ScenarioUpdateRequest(field='project',
-                                              op='add',
-                                              locate={'installer': 'apex',
-                                                      'version': 'master'},
-                                              term=add)
-        return update, scenario
-
-    @_execute
-    def test_deleteProject(self, scenario):
-        scenario['installers'][0]['versions'][0]['projects'] = filter(
-            lambda f: f['project'] != 'functest',
-            scenario['installers'][0]['versions'][0]['projects'])
-
-        update = models.ScenarioUpdateRequest(field='project',
-                                              op='delete',
-                                              locate={
-                                                  'installer': 'apex',
-                                                  'version': 'master',
-                                                  'project': 'functest'})
-        return update, scenario
-
-    @_execute
-    def test_addCustoms(self, scenario):
-        add = ['odl', 'parser', 'vping_ssh']
-        projects = scenario['installers'][0]['versions'][0]['projects']
-        functest = filter(lambda f: f['project'] == 'functest', projects)[0]
-        functest['customs'] = ['healthcheck', 'odl', 'parser', 'vping_ssh']
-        update = models.ScenarioUpdateRequest(field='customs',
-                                              op='add',
-                                              locate={
-                                                  'installer': 'apex',
-                                                  'version': 'master',
-                                                  'project': 'functest'},
-                                              term=add)
-        return update, scenario
-
-    @_execute
-    def test_deleteCustoms(self, scenario):
-        projects = scenario['installers'][0]['versions'][0]['projects']
-        functest = filter(lambda f: f['project'] == 'functest', projects)[0]
-        functest['customs'] = ['healthcheck']
-        update = models.ScenarioUpdateRequest(field='customs',
-                                              op='delete',
-                                              locate={
-                                                  'installer': 'apex',
-                                                  'version': 'master',
-                                                  'project': 'functest'},
-                                              term=['vping_ssh'])
-        return update, scenario
-
-    @_execute
-    def test_addScore(self, scenario):
-        add = models.ScenarioScore(date=str(datetime.now()), score='11/12')
-        projects = scenario['installers'][0]['versions'][0]['projects']
-        functest = filter(lambda f: f['project'] == 'functest', projects)[0]
-        functest['scores'].append(add.format())
-        update = models.ScenarioUpdateRequest(field='score',
-                                              op='add',
-                                              locate={
-                                                  'installer': 'apex',
-                                                  'version': 'master',
-                                                  'project': 'functest'},
-                                              term=add.format())
-        return update, scenario
-
-    @_execute
-    def test_addTi(self, scenario):
-        add = models.ScenarioTI(date=str(datetime.now()), status='gold')
-        projects = scenario['installers'][0]['versions'][0]['projects']
-        functest = filter(lambda f: f['project'] == 'functest', projects)[0]
-        functest['trust_indicators'].append(add.format())
-        update = models.ScenarioUpdateRequest(field='trust_indicator',
-                                              op='add',
-                                              locate={
-                                                  'installer': 'apex',
-                                                  'version': 'master',
-                                                  'project': 'functest'},
-                                              term=add.format())
-        return update, scenario
-
-    def _update_and_assert(self, update_req, new_scenario, name=None):
-        code, _ = self.update(update_req, self.scenario)
-        self.assertEqual(code, httplib.OK)
-        self._get_and_assert(_none_default(name, self.scenario),
-                             new_scenario)
-
-    def _success(self, status, new_scenario):
-        self.assertEqual(status, httplib.OK)
-        self._get_and_assert(new_scenario.get('name'), new_scenario)
-
-    def _forbidden(self, status, new_scenario):
-        self.assertEqual(status, httplib.FORBIDDEN)
-
-    def _bad_request(self, status, new_scenario):
-        self.assertEqual(status, httplib.BAD_REQUEST)
-
-
-class TestScenarioDelete(TestScenarioBase):
-    def test_notFound(self):
-        code, body = self.delete('notFound')
-        self.assertEqual(code, httplib.NOT_FOUND)
-
-    def test_success(self):
-        scenario = self.create_return_name(self.req_d)
-        code, _ = self.delete(scenario)
-        self.assertEqual(code, httplib.OK)
-        code, _ = self.get(scenario)
-        self.assertEqual(code, httplib.NOT_FOUND)
-
-
-def _none_default(check, default):
-    return check if check else default
index 83f389a..6125c95 100644 (file)
@@ -94,11 +94,18 @@ class DocParser(object):
 
     def _parse_type(self, **kwargs):
         arg = kwargs.get('arg', None)
-        body = self._get_body(**kwargs)
-        self.params.setdefault(arg, {}).update({
-            'name': arg,
-            'dataType': body
-        })
+        code = self._parse_epytext_para('code', **kwargs)
+        link = self._parse_epytext_para('link', **kwargs)
+        if code is None:
+            self.params.setdefault(arg, {}).update({
+                'name': arg,
+                'type': link
+            })
+        elif code == 'list':
+            self.params.setdefault(arg, {}).update({
+                'type': 'array',
+                'items': {'type': link}
+            })
 
     def _parse_in(self, **kwargs):
         arg = kwargs.get('arg', None)
diff --git a/utils/test/testapi/opnfv_testapi/ui/auth/base.py b/utils/test/testapi/opnfv_testapi/ui/auth/base.py
deleted file mode 100644 (file)
index bea87c4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-import random
-import string
-
-from six.moves.urllib import parse
-
-from opnfv_testapi.resources import handlers
-
-
-class BaseHandler(handlers.GenericApiHandler):
-    def __init__(self, application, request, **kwargs):
-        super(BaseHandler, self).__init__(application, request, **kwargs)
-        self.table = 'users'
-
-    def set_cookies(self, cookies):
-        for cookie_n, cookie_v in cookies:
-            self.set_secure_cookie(cookie_n, cookie_v)
-
-
-def get_token(length=30):
-    """Get random token."""
-    return ''.join(random.choice(string.ascii_lowercase)
-                   for i in range(length))
-
-
-def set_query_params(url, params):
-    """Set params in given query."""
-    url_parts = parse.urlparse(url)
-    url = parse.urlunparse((
-        url_parts.scheme,
-        url_parts.netloc,
-        url_parts.path,
-        url_parts.params,
-        parse.urlencode(params),
-        url_parts.fragment))
-    return url
diff --git a/utils/test/testapi/opnfv_testapi/ui/auth/constants.py b/utils/test/testapi/opnfv_testapi/ui/auth/constants.py
deleted file mode 100644 (file)
index 43f69d7..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-OPENID = 'openid'
-
-# OpenID parameters
-OPENID_MODE = 'openid.mode'
-OPENID_NS = 'openid.ns'
-OPENID_RETURN_TO = 'openid.return_to'
-OPENID_CLAIMED_ID = 'openid.claimed_id'
-OPENID_IDENTITY = 'openid.identity'
-OPENID_REALM = 'openid.realm'
-OPENID_NS_SREG = 'openid.ns.sreg'
-OPENID_NS_SREG_REQUIRED = 'openid.sreg.required'
-OPENID_NS_SREG_EMAIL = 'openid.sreg.email'
-OPENID_NS_SREG_FULLNAME = 'openid.sreg.fullname'
-OPENID_ERROR = 'openid.error'
-
-CSRF_TOKEN = 'csrf_token'
index 6a9d94e..318473e 100644 (file)
@@ -1,66 +1,59 @@
-from six.moves.urllib import parse
+from cas import CASClient
+from tornado import gen
+from tornado import web
 
-from opnfv_testapi.common import config
-from opnfv_testapi.ui.auth import base
-from opnfv_testapi.ui.auth import constants as const
+from opnfv_testapi.common import constants
+from opnfv_testapi.common.config import CONF
+from opnfv_testapi.db import api as dbapi
+from opnfv_testapi.resources import handlers
 
-CONF = config.Config()
 
-
-class SigninHandler(base.BaseHandler):
-    def get(self):
-        csrf_token = base.get_token()
-        return_endpoint = parse.urljoin(CONF.api_url,
-                                        CONF.osid_openid_return_to)
-        return_to = base.set_query_params(return_endpoint,
-                                          {const.CSRF_TOKEN: csrf_token})
-
-        params = {
-            const.OPENID_MODE: CONF.osid_openid_mode,
-            const.OPENID_NS: CONF.osid_openid_ns,
-            const.OPENID_RETURN_TO: return_to,
-            const.OPENID_CLAIMED_ID: CONF.osid_openid_claimed_id,
-            const.OPENID_IDENTITY: CONF.osid_openid_identity,
-            const.OPENID_REALM: CONF.api_url,
-            const.OPENID_NS_SREG: CONF.osid_openid_ns_sreg,
-            const.OPENID_NS_SREG_REQUIRED: CONF.osid_openid_sreg_required,
-        }
-        url = CONF.osid_openstack_openid_endpoint
-        url = base.set_query_params(url, params)
-        self.redirect(url=url, permanent=False)
+class SignBaseHandler(handlers.GenericApiHandler):
+    def __init__(self, application, request, **kwargs):
+        super(SignBaseHandler, self).__init__(application, request, **kwargs)
+        self.table = 'users'
+        self.cas_client = CASClient(version='2',
+                                    server_url=CONF.lfid_cas_url,
+                                    service_url='{}/{}'.format(
+                                        CONF.ui_url,
+                                        CONF.lfid_signin_return))
 
 
-class SigninReturnHandler(base.BaseHandler):
+class SigninHandler(SignBaseHandler):
     def get(self):
-        if self.get_query_argument(const.OPENID_MODE) == 'cancel':
-            self._auth_failure('Authentication canceled.')
+        self.redirect(url=(self.cas_client.get_login_url()))
 
-        openid = self.get_query_argument(const.OPENID_CLAIMED_ID)
-        user_info = {
-            'openid': openid,
-            'email': self.get_query_argument(const.OPENID_NS_SREG_EMAIL),
-            'fullname': self.get_query_argument(const.OPENID_NS_SREG_FULLNAME)
-        }
 
-        self.db_save(self.table, user_info)
-        if not self.get_secure_cookie('openid'):
-            self.set_secure_cookie('openid', openid)
-        self.redirect(url=CONF.ui_url)
+class SigninReturnHandler(SignBaseHandler):
 
-    def _auth_failure(self, message):
-        params = {'message': message}
-        url = parse.urljoin(CONF.ui_url,
-                            '/#/auth_failure?' + parse.urlencode(params))
-        self.redirect(url)
-
-
-class SignoutHandler(base.BaseHandler):
+    @web.asynchronous
+    @gen.coroutine
+    def get(self):
+        ticket = self.get_query_argument('ticket', default=None)
+        if ticket:
+            (user, attrs, _) = self.cas_client.verify_ticket(ticket=ticket)
+            login_user = {
+                'user': user,
+                'email': attrs.get('mail'),
+                'fullname': attrs.get('field_lf_full_name'),
+                'groups': constants.TESTAPI_USERS + attrs.get('group', [])
+            }
+            q_user = {'user': user}
+            db_user = yield dbapi.db_find_one(self.table, q_user)
+            if not db_user:
+                dbapi.db_save(self.table, login_user)
+            else:
+                dbapi.db_update(self.table, q_user, login_user)
+
+            self.clear_cookie(constants.TESTAPI_ID)
+            self.set_secure_cookie(constants.TESTAPI_ID, user)
+
+            self.redirect(url=CONF.ui_url)
+
+
+class SignoutHandler(SignBaseHandler):
     def get(self):
         """Handle signout request."""
-        openid = self.get_secure_cookie(const.OPENID)
-        if openid:
-            self.clear_cookie(const.OPENID)
-        params = {'openid_logout': CONF.osid_openid_logout_endpoint}
-        url = parse.urljoin(CONF.ui_url,
-                            '/#/logout?' + parse.urlencode(params))
-        self.redirect(url)
+        self.clear_cookie(constants.TESTAPI_ID)
+        logout_url = self.cas_client.get_logout_url(redirect_url=CONF.ui_url)
+        self.redirect(url=logout_url)
index 140bca5..ab86007 100644 (file)
@@ -1,24 +1,26 @@
-from tornado import gen
-from tornado import web
-
+from opnfv_testapi.common import constants
 from opnfv_testapi.common import raises
-from opnfv_testapi.ui.auth import base
+from opnfv_testapi.resources import handlers
+from opnfv_testapi.resources import models
+
+
+class User(models.ModelBase):
+    def __init__(self, user=None, email=None, fullname=None, groups=None):
+        self.user = user
+        self.email = email
+        self.fullname = fullname
+        self.groups = groups
+
 
+class UserHandler(handlers.GenericApiHandler):
+    def __init__(self, application, request, **kwargs):
+        super(UserHandler, self).__init__(application, request, **kwargs)
+        self.table = 'users'
+        self.table_cls = User
 
-class ProfileHandler(base.BaseHandler):
-    @web.asynchronous
-    @gen.coroutine
     def get(self):
-        openid = self.get_secure_cookie('openid')
-        if openid:
-            try:
-                user = yield self.db_find_one({'openid': openid})
-                self.finish_request({
-                    "openid": user.get('openid'),
-                    "email": user.get('email'),
-                    "fullname": user.get('fullname'),
-                    "is_admin": False
-                })
-            except Exception:
-                pass
-        raises.Unauthorized('Unauthorized')
+        username = self.get_secure_cookie(constants.TESTAPI_ID)
+        if username:
+            self._get_one(query={'user': username})
+        else:
+            raises.Unauthorized('Unauthorized')
index bba7a86..286a6b0 100644 (file)
@@ -1,10 +1,10 @@
-from opnfv_testapi.resources.handlers import GenericApiHandler
-from opnfv_testapi.common import config
+from opnfv_testapi.common.config import CONF
+from opnfv_testapi.resources import handlers
 
 
-class RootHandler(GenericApiHandler):
+class RootHandler(handlers.GenericApiHandler):
     def get_template_path(self):
-        return config.Config().static_path
+        return CONF.ui_static_path
 
     def get(self):
         self.render('testapi-ui/index.html')
index 955ffc8..fbd2e0e 100644 (file)
@@ -2,9 +2,10 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 
-pbr>=1.6
-setuptools>=16.0
-tornado>=3.1,<=4.3
+pbr>=2.0.0,!=2.1.0  # Apache-2.0
+setuptools>=16.0,!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2  # PSF/ZPL
+tornado>=3.1,<=4.3  # Apache-2.0
 epydoc>=0.3.1
-six>=1.9.0
-motor
+six>=1.9.0  # MIT
+motor  # Apache-2.0
+python-cas
diff --git a/utils/test/testapi/run_test.sh b/utils/test/testapi/run_test.sh
deleted file mode 100755 (executable)
index 1e05dd6..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-
-set -o errexit
-
-# Get script directory
-SCRIPTDIR=`dirname $0`
-
-echo "Running unit tests..."
-
-# Creating virtual environment
-if [ ! -z $VIRTUAL_ENV ]; then
-    venv=$VIRTUAL_ENV
-else
-    venv=$SCRIPTDIR/.venv
-    virtualenv $venv
-fi
-source $venv/bin/activate
-
-# Install requirements
-pip install -r $SCRIPTDIR/requirements.txt
-pip install -r $SCRIPTDIR/test-requirements.txt
-
-find . -type f -name "*.pyc" -delete
-
-nosetests --with-xunit \
-    --with-coverage \
-    --cover-erase \
-    --cover-package=$SCRIPTDIR/opnfv_testapi/cmd \
-    --cover-package=$SCRIPTDIR/opnfv_testapi/common \
-    --cover-package=$SCRIPTDIR/opnfv_testapi/resources \
-    --cover-package=$SCRIPTDIR/opnfv_testapi/router \
-    --cover-xml \
-    --cover-html \
-    $SCRIPTDIR/opnfv_testapi/tests
-
-exit_code=$?
-
-deactivate
-
-exit $exit_code
index ab1ef55..d9aa676 100644 (file)
@@ -23,18 +23,10 @@ setup-hooks =
 [files]
 packages =
     opnfv_testapi
-package_data =
-    opnfv_testapi =
-        static/*.*
-        static/*/*.*
-        static/*/*/*.*
-        static/*/*/*/*.*
-        static/*/*/*/*/*.*
-        static/*/*/*/*/*/*.*
-        static/*/*/*/*/*/*/*.*
+
 data_files =
-    /etc/opnfv_testapi =
-        etc/config.ini
+    /etc/opnfv_testapi = etc/config.ini
+    /usr/local/share/opnfv_testapi = 3rd_party/static/*
 
 [entry_points]
 console_scripts =
@@ -44,4 +36,3 @@ console_scripts =
 tag_build =
 tag_date = 0
 tag_svn_revision = 0
-
index 15dda96..f9d95a3 100644 (file)
@@ -1,9 +1,13 @@
 import setuptools
 
-
 __author__ = 'serena'
 
+try:
+    import multiprocessing  # noqa
+except ImportError:
+    pass
+
 
 setuptools.setup(
-    setup_requires=['pbr>=1.8'],
+    setup_requires=['pbr>=2.0.0'],
     pbr=True)
index 645687b..233f465 100644 (file)
@@ -2,7 +2,9 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 
-mock
-pytest
-coverage
-nose>=1.3.1
+coverage>=4.0,!=4.4  # Apache-2.0
+mock>=2.0  # BSD
+nose  # LGPL
+pytest  # MIT
+pytest-cov  # MIT
+pytest-mock  # MIT
diff --git a/utils/test/testapi/tools/watchdog/docker_watch.sh b/utils/test/testapi/tools/watchdog/docker_watch.sh
new file mode 100644 (file)
index 0000000..f1d8946
--- /dev/null
@@ -0,0 +1,165 @@
+#                                                               *
+#    http://www.apache.org/licenses/LICENSE-2.0                 *
+#                                                               *
+#  Unless required by applicable law or agreed to in writing,   *
+#  software distributed under the License is distributed on an  *
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+#  KIND, either express or implied.  See the License for the    *
+#  specific language governing permissions and limitations      *
+#  under the License.                                           *
+
+# This script checks if deployments are working or and then
+# starts the specified containers in case one of the containers
+# crash. The only solution is restarting docker as of now.
+
+#!/bin/bash
+
+## List of modules
+modules=(testapi reporting)
+
+## Ports of the modules
+declare -A ports=( ["testapi"]="8082" ["reporting"]="8084")
+
+## Urls to check if the modules are deployed or not ?
+declare -A urls=( ["testapi"]="http://testresults.opnfv.org/test/" \
+    ["reporting"]="http://testresults.opnfv.org/reporting/index.html")
+
+### Functions related to checking.
+
+function is_deploying() {
+    xml=$(curl -m10 "https://build.opnfv.org/ci/job/${1}-automate-master/lastBuild/api/xml?depth=1")
+    building=$(grep -oPm1 "(?<=<building>)[^<]+" <<< "$xml")
+    if [[ $building == "false" ]]
+    then
+        false
+    else
+        true
+    fi
+}
+
+function get_docker_status() {
+    status=$(service docker status | sed -n 3p | cut -d ' ' -f5)
+    echo -e "Docker status: $status"
+    if [ $status = "active" ]
+    then
+        true
+    else
+        false
+    fi
+}
+
+function check_connectivity() {
+    echo "Checking $1 connection : $2"
+    cmd=`curl --head -m10 --request GET ${2} | grep '200 OK' > /dev/null`
+    rc=$?
+    if [[ $rc == 0 ]]; then
+        true
+    else
+        false
+    fi
+}
+
+function check_modules() {
+    echo -e "Checking modules"
+    failed_modules=()
+    for module in "${modules[@]}"
+    do
+        if is_deploying $module; then
+            continue
+        fi
+        if ! check_connectivity $module "${urls[$module]}"; then
+            echo -e "$module failed"
+            failed_modules+=($module)
+        fi
+    done
+    if [ ! -z "$failed_modules" ]; then
+        echo -e "Failed Modules: $failed_modules"
+        false
+    else
+        echo -e "All modules working good"
+        exit 0
+    fi
+}
+
+### Functions related fixes.
+
+function restart_docker_fix() {
+    echo -e "Running restart_docker_fix"
+    service docker restart
+    start_containers_fix "${modules[@]}"
+}
+
+function docker_proxy_fix() {
+    echo -e "Running docker_proxy_fix"
+    fix_modules=("${@}")
+    for module in "${fix_modules[@]}"
+    do
+        echo -e "Kill docker proxy and restart containers"
+        pid=$(netstat -nlp | grep :${ports[$module]} | awk '{print $7}' | cut -d'/' -f1)
+        echo $pid
+        if [ ! -z "$pid" ]; then
+            kill $pid
+            start_container_fix $module
+        fi
+    done
+}
+
+function start_containers_fix() {
+    start_modules=("${@}")
+    for module in "${start_modules[@]}"
+    do
+        start_container_fix $module
+    done
+}
+
+function start_container_fix() {
+    echo -e "Starting a container $module"
+    sudo docker stop $module
+    sudo docker start $module
+    sleep 5
+    if ! check_connectivity $module "${urls[$module]}"; then
+        echo -e "Starting an old container $module_old"
+        sudo docker stop $module
+        sudo docker start $module"_old"
+        sleep 5
+    fi
+}
+
+### Main Flow
+
+echo -e
+echo -e "WatchDog Started"
+echo -e
+echo -e `date "+%Y-%m-%d %H:%M:%S.%N"`
+echo -e
+
+## If the problem is related to docker daemon
+
+if ! get_docker_status; then
+    restart_docker_fix
+    if ! check_modules; then
+        echo -e "Watchdog failed while restart_docker_fix"
+    fi
+    exit
+fi
+
+## If the problem is related to docker proxy
+
+if ! check_modules; then
+    docker_proxy_fix "${failed_modules[@]}"
+fi
+
+## If any other problem : restart docker
+
+if ! check_modules; then
+    restart_docker_fix
+fi
+
+## If nothing works out
+
+if ! check_modules; then
+    echo -e "Watchdog failed"
+fi
+
+sudo docker ps
+sudo docker images
\ No newline at end of file
index 81c9dfa..d300f1a 100644 (file)
@@ -4,7 +4,7 @@
 # and then run "tox" from this directory.
 
 [tox]
-envlist = py27,pep8
+envlist = pep8,py27
 skipsdist = True
 sitepackages = True
 
@@ -16,9 +16,11 @@ deps =
   -rtest-requirements.txt
 commands=
   py.test \
-    --basetemp={envtmpdir} \
-    --cov \
-    {posargs}
+  --basetemp={envtmpdir} \
+  --cov \
+  --cov-report term-missing \
+  --cov-report xml \
+  {posargs}
 setenv=
   HOME = {envtmpdir}
   PYTHONPATH = {toxinidir}
index 7e0dd55..9c24377 100644 (file)
@@ -40,5 +40,6 @@ def backup(args):
     cmd = ['mongodump', '-o', '%s' % out]
     execute(cmd, args)
 
+
 if __name__ == '__main__':
     main(backup, parser)
index ba4334a..f759592 100644 (file)
@@ -85,5 +85,6 @@ def update(args):
     rename_fields(fields_old2New)
     rename_collections(collections_old2New)
 
+
 if __name__ == '__main__':
     main(update, parser)
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/.dockerignore b/utils/test/vnfcatalogue/VNF_Catalogue/.dockerignore
deleted file mode 100644 (file)
index 93f1361..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-node_modules
-npm-debug.log
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/Dockerfile b/utils/test/vnfcatalogue/VNF_Catalogue/Dockerfile
deleted file mode 100644 (file)
index 5df8eb5..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#############################################
-#   Docker container for VNF_Catalogue WebApp
-#############################################
-# Purpose: Don't run it from here! Use docker-compose(See README.md)
-#
-# Maintained by Kumar Rishabh :: penguinRaider
-##
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-
-FROM node:boron
-MAINTAINER KumarRishabh::penguinRaider <shailrishabh@gmail.com>
-LABEL version="v0.0.1" description="Open Source VNF_Catalogue for OPNFV"
-
-ENV DB_HOST mysql
-ENV DB_USER vnf_user
-ENV DB_PASSWORD vnf_password
-ENV DB_DATABASE vnf_catalogue
-
-RUN mkdir -p /usr/src/app
-WORKDIR /usr/src/app
-
-COPY package.json /usr/src/app/
-
-RUN npm install
-
-COPY . /usr/src/app
-
-EXPOSE 3000
-
-# We wait for mysql service to come up before starting the server using a 3rd_party script.
-CMD [ "./migration/3rd_party/wait-for-it/wait-for-it.sh", "mysql:3306", "-t", "0", "--", "npm", "start" ]
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/README.md b/utils/test/vnfcatalogue/VNF_Catalogue/README.md
deleted file mode 100644 (file)
index 91179f5..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#VNF_Catalogue Nodejs + Jade + MySql server
-
-
-## Quickstart
-
-First install docker and docker-compose. This multicontainer app uses
-docker-compose to organize the vnf_catalogue web_app
-
-The use
-    ```docker-compose up```
-
-set time zone(optional)
-        Set same timezone in both nodejs server and mysql server. Something
-        similar to below can be used:
-        ``` SET GLOBAL time_zone = '+00:00'; ```
-
-
-The server would be accessible at ```ip_address:3000```
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/app.js b/utils/test/vnfcatalogue/VNF_Catalogue/app.js
deleted file mode 100644 (file)
index 4b6add2..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var express = require('express');
-var path = require('path');
-var favicon = require('serve-favicon');
-var logger = require('morgan');
-var cookieParser = require('cookie-parser');
-var bodyParser = require('body-parser');
-var validator = require('express-validator');
-
-var routes = require('./routes/index');
-var search_projects = require('./routes/search_projects');
-var project_profile = require('./routes/project_profile');
-var add_project = require('./routes/add_project');
-var add_tag = require('./routes/add_tag');
-var search_tag = require('./routes/search_tag');
-var search_vnf = require('./routes/search_vnf');
-var vnf_tag_association = require('./routes/vnf_tag_association');
-
-
-var app = express();
-
-// view engine setup
-app.set('views', path.join(__dirname, 'views'));
-app.set('view engine', 'jade');
-
-db_pool = require('./database').pool;
-
-// Database
-//var db = require('mysql2');
-
-// uncomment after placing your favicon in /public
-//app.use(favicon(__dirname + '/public/favicon.ico'));
-app.use(logger('dev'));
-app.use(bodyParser.json());
-app.use(bodyParser.urlencoded({ extended: false }));
-app.use(validator());
-app.use(cookieParser());
-app.use(express.static(path.join(__dirname, 'public')));
-
-// Make our db accessible to our router
-app.use(function(req,res,next){
-    //db_pool size 50 default
-    req.db_pool = db_pool;
-    next();
-});
-
-app.use('/', routes);
-app.use('/search_projects', search_projects);
-app.use('/project_profile', project_profile);
-app.use('/add_project', add_project);
-app.use('/add_tag', add_tag);
-app.use('/search_tag', search_tag);
-app.use('/search_vnf', search_vnf);
-app.use('/vnf_tag_association', vnf_tag_association);
-// Some Error handling for now #TODO Remove
-
-/// catch 404 and forwarding to error handler
-app.use(function(req, res, next) {
-    var err = new Error('Not Found');
-    err.status = 404;
-    next(err);
-});
-
-
-// development error handler
-// will print stacktrace
-if (app.get('env') === 'development') {
-    app.use(function(err, req, res, next) {
-        res.status(err.status || 500);
-        res.render('error', {
-            message: err.message,
-            error: err
-        });
-    });
-}
-
-// production error handler
-// no stacktraces leaked to user
-app.use(function(err, req, res, next) {
-    res.status(err.status || 500);
-    res.render('error', {
-        message: err.message,
-        error: {}
-    });
-});
-
-module.exports = app;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/bin/www b/utils/test/vnfcatalogue/VNF_Catalogue/bin/www
deleted file mode 100644 (file)
index 3cfbf77..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env node
-var debug = require('debug')('my-application');
-var app = require('../app');
-
-app.set('port', process.env.PORT || 3000);
-
-var server = app.listen(app.get('port'), function() {
-  debug('Express server listening on port ' + server.address().port);
-});
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/database.js b/utils/test/vnfcatalogue/VNF_Catalogue/database.js
deleted file mode 100644 (file)
index 4fa8be1..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var mysql = require('mysql');
-
-var pool = mysql.createPool({
-  host: process.env.DB_HOST,
-  user: process.env.DB_USER,
-  password: process.env.DB_PASSWORD,
-  database: process.env.DB_DATABASE,
-  connectionLimit: 50,
-  supportBigNumbers: true,
-  multipleStatements: true,
-  dateStrings: 'date'
-});
-
-exports.pool = pool;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/docker-compose.yml b/utils/test/vnfcatalogue/VNF_Catalogue/docker-compose.yml
deleted file mode 100644 (file)
index a0ddfa4..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-##################################################################
-#   Docker-Compose for setting up and running vnf_catalogue webapp
-##################################################################
-# Purpose: To setup and run vnf_catalogue webapp
-# Usage: docker-compose up
-#
-# The webapp would be accessible at ip_address:3000
-#
-# Maintained by Kumar Rishabh :: penguinRaider
-##
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-
-version: "2"
-services:
-    mysql:
-    # mysql service built on top of vanilla mysql container.
-    # Defines mysql credentials.
-
-        image: mysql
-        container_name: vnf_catalogue_database
-        environment:
-            - MYSQL_USER=vnf_user
-            - MYSQL_PASSWORD=vnf_password
-            - MYSQL_DATABASE=vnf_catalogue
-            - MYSQL_ROOT_PASSWORD=root
-    vnf_catalogue:
-    # The vnf_catalogue webapp service.
-        build: .
-        container_name: vnf_catalogue_webapp
-        depends_on:
-            - mysql
-        # Port on which the node.js server would be exposed <host:container>
-        # To change host port to say 80 use 80:3000
-
-        ports:
-            - "3000:3000"
-    vnf_catalogue_migrate:
-    # We define another service for database migration. This service will
-    # migrate the database schema.(Dockerfile resides in migration
-    # directory).
-
-        build: ./migration
-        container_name: vnf_catalogue_migrate
-        depends_on:
-            - mysql
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/docker_commands.sh b/utils/test/vnfcatalogue/VNF_Catalogue/docker_commands.sh
deleted file mode 100644 (file)
index 3be98ce..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-sh ./3rd_party/wait-for-it/wait-for-it.sh mysql:3306 -t 0
-node migrate
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/migration/3rd_party/wait-for-it/LICENSE b/utils/test/vnfcatalogue/VNF_Catalogue/migration/3rd_party/wait-for-it/LICENSE
deleted file mode 100644 (file)
index bd18d0c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-Copyright (c) 2016 Giles Hall
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/migration/3rd_party/wait-for-it/README.md b/utils/test/vnfcatalogue/VNF_Catalogue/migration/3rd_party/wait-for-it/README.md
deleted file mode 100644 (file)
index 900b757..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-# HELP NEEDED
-
-### March 13, 2017 update
-
-Since I posted this request for help, I've had a dozen or so responses which I am now sorting through.  Applicants need to fill out [this](https://goo.gl/forms/GKCBFxaloaU47aky1) survey by March 17th.  I will select, notify and announce the new volunteer(s) on March 19th.  Once this is done, me and my team will work through the backlog of issues amd pull requests.  Thanks for your paitence.
-
-### Old request follows:
-
-Hi there!  I wrote `wait-for-it` in order to help me orchestrate containers I operate at my day job.  I thought it was a neat little script, so I published it.  I assumed I would be its only user, but that's not what happened!  `wait-for-it` has received more stars then all of my other public repositories put together.  I had no idea this tool would solicit such an audience, and I was equally unprepared to carve out the time required to address my user's issues and patches.  I would like to solicit a volunteer from the community who would be willing to be a co-maintainer of this repository.  If this is something you might be interested in, please email me at `waitforit@polymerase.org`.  Thanks!
-
-## wait-for-it
-
-`wait-for-it.sh` is a pure bash script that will wait on the availability of a host and TCP port.  It is useful for synchronizing the spin-up of interdependent services, such as linked docker containers.  Since it is a pure bash script, it does not have any external dependencies.
-
-## Usage
-
-```
-wait-for-it.sh host:port [-s] [-t timeout] [-- command args]
--h HOST | --host=HOST       Host or IP under test
--p PORT | --port=PORT       TCP port under test
-                            Alternatively, you specify the host and port as host:port
--s | --strict               Only execute subcommand if the test succeeds
--q | --quiet                Don't output any status messages
--t TIMEOUT | --timeout=TIMEOUT
-                            Timeout in seconds, zero for no timeout
--- COMMAND ARGS             Execute command with args after the test finishes
-```
-
-## Examples
-
-For example, let's test to see if we can access port 80 on www.google.com, and if it is available, echo the message `google is up`.
-
-```
-$ ./wait-for-it.sh www.google.com:80 -- echo "google is up"
-wait-for-it.sh: waiting 15 seconds for www.google.com:80
-wait-for-it.sh: www.google.com:80 is available after 0 seconds
-google is up
-```
-
-You can set your own timeout with the `-t` or `--timeout=` option.  Setting the timeout value to 0 will disable the timeout:
-
-```
-$ ./wait-for-it.sh -t 0 www.google.com:80 -- echo "google is up"
-wait-for-it.sh: waiting for www.google.com:80 without a timeout
-wait-for-it.sh: www.google.com:80 is available after 0 seconds
-google is up
-```
-
-The subcommand will be executed regardless if the service is up or not.  If you wish to execute the subcommand only if the service is up, add the `--strict` argument. In this example, we will test port 81 on www.google.com which will fail:
-
-```
-$ ./wait-for-it.sh www.google.com:81 --timeout=1 --strict -- echo "google is up"
-wait-for-it.sh: waiting 1 seconds for www.google.com:81
-wait-for-it.sh: timeout occurred after waiting 1 seconds for www.google.com:81
-wait-for-it.sh: strict mode, refusing to execute subprocess
-```
-
-If you don't want to execute a subcommand, leave off the `--` argument.  This way, you can test the exit condition of `wait-for-it.sh` in your own scripts, and determine how to proceed:
-
-```
-$ ./wait-for-it.sh www.google.com:80
-wait-for-it.sh: waiting 15 seconds for www.google.com:80
-wait-for-it.sh: www.google.com:80 is available after 0 seconds
-$ echo $?
-0
-$ ./wait-for-it.sh www.google.com:81
-wait-for-it.sh: waiting 15 seconds for www.google.com:81
-wait-for-it.sh: timeout occurred after waiting 15 seconds for www.google.com:81
-$ echo $?
-124
-```
-
-## Thanks
-
-I wrote this script for my employer, [Ginkgo Bioworks](http://www.ginkgobioworks.com/), who was kind enough to let me release it as an open source tool.  We are always looking to [hire](https://jobs.lever.co/ginkgobioworks) talented folks who are interested in working in the field of synthetic biology.
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/migration/3rd_party/wait-for-it/wait-for-it.sh b/utils/test/vnfcatalogue/VNF_Catalogue/migration/3rd_party/wait-for-it/wait-for-it.sh
deleted file mode 100755 (executable)
index eca6c3b..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-#!/usr/bin/env bash
-#   Use this script to test if a given TCP host/port are available
-
-cmdname=$(basename $0)
-
-echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
-
-usage()
-{
-    cat << USAGE >&2
-Usage:
-    $cmdname host:port [-s] [-t timeout] [-- command args]
-    -h HOST | --host=HOST       Host or IP under test
-    -p PORT | --port=PORT       TCP port under test
-                                Alternatively, you specify the host and port as host:port
-    -s | --strict               Only execute subcommand if the test succeeds
-    -q | --quiet                Don't output any status messages
-    -t TIMEOUT | --timeout=TIMEOUT
-                                Timeout in seconds, zero for no timeout
-    -- COMMAND ARGS             Execute command with args after the test finishes
-USAGE
-    exit 1
-}
-
-wait_for()
-{
-    if [[ $TIMEOUT -gt 0 ]]; then
-        echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT"
-    else
-        echoerr "$cmdname: waiting for $HOST:$PORT without a timeout"
-    fi
-    start_ts=$(date +%s)
-    while :
-    do
-        (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1
-        result=$?
-        if [[ $result -eq 0 ]]; then
-            end_ts=$(date +%s)
-            echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds"
-            break
-        fi
-        sleep 1
-    done
-    return $result
-}
-
-wait_for_wrapper()
-{
-    # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
-    if [[ $QUIET -eq 1 ]]; then
-        timeout $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
-    else
-        timeout $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
-    fi
-    PID=$!
-    trap "kill -INT -$PID" INT
-    wait $PID
-    RESULT=$?
-    if [[ $RESULT -ne 0 ]]; then
-        echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT"
-    fi
-    return $RESULT
-}
-
-# process arguments
-while [[ $# -gt 0 ]]
-do
-    case "$1" in
-        *:* )
-        hostport=(${1//:/ })
-        HOST=${hostport[0]}
-        PORT=${hostport[1]}
-        shift 1
-        ;;
-        --child)
-        CHILD=1
-        shift 1
-        ;;
-        -q | --quiet)
-        QUIET=1
-        shift 1
-        ;;
-        -s | --strict)
-        STRICT=1
-        shift 1
-        ;;
-        -h)
-        HOST="$2"
-        if [[ $HOST == "" ]]; then break; fi
-        shift 2
-        ;;
-        --host=*)
-        HOST="${1#*=}"
-        shift 1
-        ;;
-        -p)
-        PORT="$2"
-        if [[ $PORT == "" ]]; then break; fi
-        shift 2
-        ;;
-        --port=*)
-        PORT="${1#*=}"
-        shift 1
-        ;;
-        -t)
-        TIMEOUT="$2"
-        if [[ $TIMEOUT == "" ]]; then break; fi
-        shift 2
-        ;;
-        --timeout=*)
-        TIMEOUT="${1#*=}"
-        shift 1
-        ;;
-        --)
-        shift
-        CLI="$@"
-        break
-        ;;
-        --help)
-        usage
-        ;;
-        *)
-        echoerr "Unknown argument: $1"
-        usage
-        ;;
-    esac
-done
-
-if [[ "$HOST" == "" || "$PORT" == "" ]]; then
-    echoerr "Error: you need to provide a host and port to test."
-    usage
-fi
-
-TIMEOUT=${TIMEOUT:-15}
-STRICT=${STRICT:-0}
-CHILD=${CHILD:-0}
-QUIET=${QUIET:-0}
-
-if [[ $CHILD -gt 0 ]]; then
-    wait_for
-    RESULT=$?
-    exit $RESULT
-else
-    if [[ $TIMEOUT -gt 0 ]]; then
-        wait_for_wrapper
-        RESULT=$?
-    else
-        wait_for
-        RESULT=$?
-    fi
-fi
-
-if [[ $CLI != "" ]]; then
-    if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then
-        echoerr "$cmdname: strict mode, refusing to execute subprocess"
-        exit $RESULT
-    fi
-    exec $CLI
-else
-    exit $RESULT
-fi
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/migration/Dockerfile b/utils/test/vnfcatalogue/VNF_Catalogue/migration/Dockerfile
deleted file mode 100644 (file)
index a046664..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-###############################################################
-#   Docker container for VNF_Catalogue Schema Migration Service
-###############################################################
-# Purpose: Don't run it from here! Use docker-compose(See README.md)
-#
-# Maintained by Kumar Rishabh :: penguinRaider
-##
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-
-FROM node:boron
-MAINTAINER KumarRishabh::penguinRaider <shailrishabh@gmail.com>
-LABEL version="v0.0.1" description="Open Source VNF_Catalogue for OPNFV"
-
-ENV DB_HOST mysql
-ENV DB_USER vnf_user
-ENV DB_PASSWORD vnf_password
-ENV DB_DATABASE vnf_catalogue
-
-RUN mkdir -p /usr/src/app
-WORKDIR /usr/src/app
-
-COPY package.json /usr/src/app/
-
-RUN npm install
-
-COPY . /usr/src/app
-
-# The ordering of events should be coming up of mysql service and then migration
-# of schema for the database. To enforce this causal relationship we use a 3rd_party script.
-CMD [ "./3rd_party/wait-for-it/wait-for-it.sh", "mysql:3306", "-t", "0", "--", "node", "migrate"]
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/migration/migrate.js b/utils/test/vnfcatalogue/VNF_Catalogue/migration/migrate.js
deleted file mode 100644 (file)
index 3f4d892..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh(penguinRaider) and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var knex = require('knex')({
-    client: 'mysql',
-    connection: {
-        host     : process.env.DB_HOST,
-        user     : process.env.DB_USER,
-        password : process.env.DB_PASSWORD,
-        database : process.env.DB_DATABASE,
-        charset  : 'utf8'
-    }
-});
-var Schema = require('./schema');
-var sequence = require('when/sequence');
-var _ = require('lodash');
-function createTable(tableName) {
-    return knex.schema.createTable(tableName, function (table) {
-    var column;
-    var columnKeys = _.keys(Schema[tableName]);
-    _.each(columnKeys, function (key) {
-        if (Schema[tableName][key].type === 'text' && Schema[tableName][key].hasOwnProperty('fieldtype')) {
-        column = table[Schema[tableName][key].type](key, Schema[tableName][key].fieldtype);
-        }
-        else if (Schema[tableName][key].type === 'enum' && Schema[tableName][key].hasOwnProperty('values') && Schema[tableName][key].nullable === true) {
-        console.log(Schema[tableName][key].values);
-        column = table[Schema[tableName][key].type](key, Schema[tableName][key].values).nullable();
-        }
-        else if (Schema[tableName][key].type === 'enum' && Schema[tableName][key].hasOwnProperty('values')) {
-        console.log(Schema[tableName][key].values);
-        column = table[Schema[tableName][key].type](key, Schema[tableName][key].values).notNullable();
-        }
-        else if (Schema[tableName][key].type === 'string' && Schema[tableName][key].hasOwnProperty('maxlength')) {
-        column = table[Schema[tableName][key].type](key, Schema[tableName][key].maxlength);
-        }
-        else {
-        column = table[Schema[tableName][key].type](key);
-        }
-        if (Schema[tableName][key].hasOwnProperty('nullable') && Schema[tableName][key].nullable === true) {
-        column.nullable();
-        }
-        else {
-        column.notNullable();
-        }
-        if (Schema[tableName][key].hasOwnProperty('primary') && Schema[tableName][key].primary === true) {
-        column.primary();
-        }
-        if (Schema[tableName][key].hasOwnProperty('unique') && Schema[tableName][key].unique) {
-        column.unique();
-        }
-        if (Schema[tableName][key].hasOwnProperty('unsigned') && Schema[tableName][key].unsigned) {
-        column.unsigned();
-        }
-        if (Schema[tableName][key].hasOwnProperty('references')) {
-        column.references(Schema[tableName][key].references);
-        }
-        if (Schema[tableName][key].hasOwnProperty('defaultTo')) {
-        column.defaultTo(Schema[tableName][key].defaultTo);
-        }
-    });
-    });
-}
-function createTables () {
-    var tables = [];
-    var tableNames = _.keys(Schema);
-    tables = _.map(tableNames, function (tableName) {
-    return function () {
-        return createTable(tableName);
-    };
-    });
-    return sequence(tables);
-}
-createTables()
-.then(function() {
-    console.log('Tables created!!');
-    process.exit(0);
-})
-.catch(function (error) {
-    throw error;
-});
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/migration/package.json b/utils/test/vnfcatalogue/VNF_Catalogue/migration/package.json
deleted file mode 100644 (file)
index 65ff324..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "name": "VNF_Catalogue_migration",
-  "version": "0.0.1",
-  "private": true,
-  "scripts": {
-    "start": "node ./bin/www"
-  },
-  "dependencies": {
-    "bookshelf": "*",
-    "knex": "*",
-    "lodash": "*",
-    "mysql": "^2.13.0",
-    "when": "*"
-  }
-}
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/migration/schema.js b/utils/test/vnfcatalogue/VNF_Catalogue/migration/schema.js
deleted file mode 100644 (file)
index 4a7559a..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh(penguinRaider) and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-var Schema = {
-    photo: {
-        photo_id: {type: 'increments', nullable: false, primary: true},
-        photo_url: {type: 'string', maxlength: 254, nullable: false}
-    },
-    user: {
-        user_id: {type: 'increments', nullable: false, primary: true},
-        user_name: {type: 'string', maxlength: 254, nullable: false},
-        password: {type: 'string', maxlength: 150, nullable: false},
-        email_id: {type: 'string', maxlength: 254, nullable: false, unique: true, validations: {isEmail: true}},
-        photo_id: {type: 'integer', nullable: true, unsigned: true, references: 'photo.photo_id'},
-        company: {type: 'string', maxlength: 254, nullable: false},
-        introduction: {type: 'string', maxlength: 510, nullable: false},
-        last_login: {type: 'dateTime', nullable: true},
-        created_at: {type: 'dateTime', nullable: false},
-    },
-    vnf: {
-        vnf_id: {type: 'increments', nullable: false, primary: true},
-        vnf_name: {type: 'string', maxlength: 254, nullable: false},
-        repo_url: {type: 'string', maxlength: 254, nullable: false},
-        photo_id: {type: 'integer', nullable: true, unsigned: true, references: 'photo.photo_id'},
-        submitter_id: {type: 'integer', nullable: false, unsigned: true, references: 'user.user_id'},
-        lines_of_code: {type: 'integer', nullable: true, unsigned: true},
-        versions: {type: 'integer', nullable: true, unsigned: true},
-        no_of_developers: {type: 'integer', nullable: true, unsigned: true},
-        no_of_stars: {type: 'integer', nullable: true, unsigned: true},
-        license: {type: 'enum', nullable: false, values: ['MIT', 'GPL', 'GPL_V2', 'BSD', 'APACHE']},
-        opnfv_indicator: {type: 'enum', nullable: false, values: ['gold', 'silver', 'platinum']},
-        complexity: {type: 'enum', nullable: true, values: ['low', 'medium', 'high']},
-        activity: {type: 'enum', nullable: true, values: ['low', 'medium', 'high']},
-        last_updated: {type: 'dateTime', nullable: true},
-    },
-    tag: {
-        tag_id: {type: 'increments', nullable: false, primary: true},
-        tag_name: {type: 'string', maxlength: 150, nullable: false}
-    },
-    vnf_tags: {
-        vnf_tag_id: {type: 'increments', nullable: false, primary: true},
-        tag_id: {type: 'integer', nullable: false, unsigned: true, references: 'tag.tag_id'},
-        vnf_id: {type: 'integer', nullable: false, unsigned: true, references: 'vnf.vnf_id'},
-    },
-    vnf_contributors: {
-        vnf_contributors_id: {type: 'increments', nullable: false, primary: true},
-        user_id: {type: 'integer', nullable: false, unsigned: true, references: 'user.user_id'},
-        vnf_id: {type: 'integer', nullable: false, unsigned: true, references: 'vnf.vnf_id'},
-        created_at: {type: 'dateTime', nullable: false},
-    }
-};
-module.exports = Schema;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/package.json b/utils/test/vnfcatalogue/VNF_Catalogue/package.json
deleted file mode 100644 (file)
index b7a6c23..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-{
-    "name": "VNF_Catalogue",
-    "version": "0.0.1",
-    "private": true,
-    "scripts": {
-        "start": "node ./bin/www"
-    },
-    "dependencies": {
-        "body-parser": "~1.15.1",
-        "cookie-parser": "~1.4.3",
-        "debug": "~2.2.0",
-        "express": "~4.13.4",
-        "jade": "~1.11.0",
-        "morgan": "~1.7.0",
-        "serve-favicon": "~2.3.0",
-        "mysql": "*",
-        "express-validator": "*",
-        "nodemon": "*",
-        "async": "*",
-        "multer": "*",
-        "octonode": "*",
-        "bookshelf": "*",
-        "knex": "*",
-        "when": "*",
-        "lodash": "*"
-    }
-}
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/.DS_Store b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/.DS_Store
deleted file mode 100644 (file)
index 2828ef6..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/.DS_Store and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/LICENSE b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/LICENSE
deleted file mode 100644 (file)
index 44bd03e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014-2017 Materialize
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/README.md b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/README.md
deleted file mode 100644 (file)
index 497b01a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-![alt tag](https://raw.github.com/dogfalo/materialize/master/images/materialize.gif)
-===========
-
-[![Travis CI](https://travis-ci.org/Dogfalo/materialize.svg?branch=master)](https://travis-ci.org/Dogfalo/materialize)[![devDependency Status](https://david-dm.org/Dogfalo/materialize/dev-status.svg)](https://david-dm.org/Dogfalo/materialize#info=devDependencies)[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/Dogfalo/materialize?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-
-[Materialize](http://materializecss.com/), a CSS Framework based on material design
-
-### Current Version : v0.97.8
-
-## Sass Requirements:
-- Ruby Sass 3.3+, LibSass 0.6+
-
-## Supported Browsers:
-Chrome 35+, Firefox 31+, Safari 7+, IE 10+
-
-## Changelog
-- v0.97.8 (October 30th, 2016)
-  - **Refactored Modal plugin**
-  - Tabs now supported in navbar
-  - Chips data can now be reinitiailized
-  - Minor side nav fixes
-  - FAB to toolbar component added
-  - Fixed dropdown options bug
-- v0.97.7 (July 23rd, 2016)
-  - Basic horizontal cards
-  - Carousel bug fixes and new features
-  - Updated sidenav styles and new component
-  - Meteor package now supports Sass
-  - Autocomplete form component
-  - Chips jQuery plugin
-- v0.97.6 (April 1st, 2016)
-  - **Removed deprecated material icons from project**
-  - **Changed /font directory to /fonts**
-  - Datepicker and ScrollSpy now compatible with jQuery 2.2.x
-  - Responsive tables now work with empty cells
-  - Added focus states to checkboxes, switches, and radio buttons
-  - Sidenav and Modals no longer cause flicker with scrollbar
-  - Materialbox overflow and z-index issues fixed
-  - Added new option for Card actions within a Card reveal
-- v0.97.5 (December 21st, 2015)
-  - Fixed Meteor package crash
-
-
-
-## Contributing
-[Please read CONTRIBUTING.md for more information](CONTRIBUTING.md)
-
-## Testing
-We use Jasmine as our testing framework and we're trying to write a robust test suite for our components. If you want to help, [here's a starting guide on how to write tests in Jasmine](https://docs.google.com/document/d/1dVM6qGt_b_y9RRhr9X7oZfFydaJIEqB9CT7yekv-4XE/edit?usp=sharing)
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/css/materialize.css b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/css/materialize.css
deleted file mode 100644 (file)
index 27de210..0000000
+++ /dev/null
@@ -1,8582 +0,0 @@
-/*!
- * Materialize v0.98.0 (http://materializecss.com)
- * Copyright 2014-2015 Materialize
- * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE)
- */
-.materialize-red {
-  background-color: #e51c23 !important;
-}
-
-.materialize-red-text {
-  color: #e51c23 !important;
-}
-
-.materialize-red.lighten-5 {
-  background-color: #fdeaeb !important;
-}
-
-.materialize-red-text.text-lighten-5 {
-  color: #fdeaeb !important;
-}
-
-.materialize-red.lighten-4 {
-  background-color: #f8c1c3 !important;
-}
-
-.materialize-red-text.text-lighten-4 {
-  color: #f8c1c3 !important;
-}
-
-.materialize-red.lighten-3 {
-  background-color: #f3989b !important;
-}
-
-.materialize-red-text.text-lighten-3 {
-  color: #f3989b !important;
-}
-
-.materialize-red.lighten-2 {
-  background-color: #ee6e73 !important;
-}
-
-.materialize-red-text.text-lighten-2 {
-  color: #ee6e73 !important;
-}
-
-.materialize-red.lighten-1 {
-  background-color: #ea454b !important;
-}
-
-.materialize-red-text.text-lighten-1 {
-  color: #ea454b !important;
-}
-
-.materialize-red.darken-1 {
-  background-color: #d0181e !important;
-}
-
-.materialize-red-text.text-darken-1 {
-  color: #d0181e !important;
-}
-
-.materialize-red.darken-2 {
-  background-color: #b9151b !important;
-}
-
-.materialize-red-text.text-darken-2 {
-  color: #b9151b !important;
-}
-
-.materialize-red.darken-3 {
-  background-color: #a21318 !important;
-}
-
-.materialize-red-text.text-darken-3 {
-  color: #a21318 !important;
-}
-
-.materialize-red.darken-4 {
-  background-color: #8b1014 !important;
-}
-
-.materialize-red-text.text-darken-4 {
-  color: #8b1014 !important;
-}
-
-.red {
-  background-color: #F44336 !important;
-}
-
-.red-text {
-  color: #F44336 !important;
-}
-
-.red.lighten-5 {
-  background-color: #FFEBEE !important;
-}
-
-.red-text.text-lighten-5 {
-  color: #FFEBEE !important;
-}
-
-.red.lighten-4 {
-  background-color: #FFCDD2 !important;
-}
-
-.red-text.text-lighten-4 {
-  color: #FFCDD2 !important;
-}
-
-.red.lighten-3 {
-  background-color: #EF9A9A !important;
-}
-
-.red-text.text-lighten-3 {
-  color: #EF9A9A !important;
-}
-
-.red.lighten-2 {
-  background-color: #E57373 !important;
-}
-
-.red-text.text-lighten-2 {
-  color: #E57373 !important;
-}
-
-.red.lighten-1 {
-  background-color: #EF5350 !important;
-}
-
-.red-text.text-lighten-1 {
-  color: #EF5350 !important;
-}
-
-.red.darken-1 {
-  background-color: #E53935 !important;
-}
-
-.red-text.text-darken-1 {
-  color: #E53935 !important;
-}
-
-.red.darken-2 {
-  background-color: #D32F2F !important;
-}
-
-.red-text.text-darken-2 {
-  color: #D32F2F !important;
-}
-
-.red.darken-3 {
-  background-color: #C62828 !important;
-}
-
-.red-text.text-darken-3 {
-  color: #C62828 !important;
-}
-
-.red.darken-4 {
-  background-color: #B71C1C !important;
-}
-
-.red-text.text-darken-4 {
-  color: #B71C1C !important;
-}
-
-.red.accent-1 {
-  background-color: #FF8A80 !important;
-}
-
-.red-text.text-accent-1 {
-  color: #FF8A80 !important;
-}
-
-.red.accent-2 {
-  background-color: #FF5252 !important;
-}
-
-.red-text.text-accent-2 {
-  color: #FF5252 !important;
-}
-
-.red.accent-3 {
-  background-color: #FF1744 !important;
-}
-
-.red-text.text-accent-3 {
-  color: #FF1744 !important;
-}
-
-.red.accent-4 {
-  background-color: #D50000 !important;
-}
-
-.red-text.text-accent-4 {
-  color: #D50000 !important;
-}
-
-.pink {
-  background-color: #e91e63 !important;
-}
-
-.pink-text {
-  color: #e91e63 !important;
-}
-
-.pink.lighten-5 {
-  background-color: #fce4ec !important;
-}
-
-.pink-text.text-lighten-5 {
-  color: #fce4ec !important;
-}
-
-.pink.lighten-4 {
-  background-color: #f8bbd0 !important;
-}
-
-.pink-text.text-lighten-4 {
-  color: #f8bbd0 !important;
-}
-
-.pink.lighten-3 {
-  background-color: #f48fb1 !important;
-}
-
-.pink-text.text-lighten-3 {
-  color: #f48fb1 !important;
-}
-
-.pink.lighten-2 {
-  background-color: #f06292 !important;
-}
-
-.pink-text.text-lighten-2 {
-  color: #f06292 !important;
-}
-
-.pink.lighten-1 {
-  background-color: #ec407a !important;
-}
-
-.pink-text.text-lighten-1 {
-  color: #ec407a !important;
-}
-
-.pink.darken-1 {
-  background-color: #d81b60 !important;
-}
-
-.pink-text.text-darken-1 {
-  color: #d81b60 !important;
-}
-
-.pink.darken-2 {
-  background-color: #c2185b !important;
-}
-
-.pink-text.text-darken-2 {
-  color: #c2185b !important;
-}
-
-.pink.darken-3 {
-  background-color: #ad1457 !important;
-}
-
-.pink-text.text-darken-3 {
-  color: #ad1457 !important;
-}
-
-.pink.darken-4 {
-  background-color: #880e4f !important;
-}
-
-.pink-text.text-darken-4 {
-  color: #880e4f !important;
-}
-
-.pink.accent-1 {
-  background-color: #ff80ab !important;
-}
-
-.pink-text.text-accent-1 {
-  color: #ff80ab !important;
-}
-
-.pink.accent-2 {
-  background-color: #ff4081 !important;
-}
-
-.pink-text.text-accent-2 {
-  color: #ff4081 !important;
-}
-
-.pink.accent-3 {
-  background-color: #f50057 !important;
-}
-
-.pink-text.text-accent-3 {
-  color: #f50057 !important;
-}
-
-.pink.accent-4 {
-  background-color: #c51162 !important;
-}
-
-.pink-text.text-accent-4 {
-  color: #c51162 !important;
-}
-
-.purple {
-  background-color: #9c27b0 !important;
-}
-
-.purple-text {
-  color: #9c27b0 !important;
-}
-
-.purple.lighten-5 {
-  background-color: #f3e5f5 !important;
-}
-
-.purple-text.text-lighten-5 {
-  color: #f3e5f5 !important;
-}
-
-.purple.lighten-4 {
-  background-color: #e1bee7 !important;
-}
-
-.purple-text.text-lighten-4 {
-  color: #e1bee7 !important;
-}
-
-.purple.lighten-3 {
-  background-color: #ce93d8 !important;
-}
-
-.purple-text.text-lighten-3 {
-  color: #ce93d8 !important;
-}
-
-.purple.lighten-2 {
-  background-color: #ba68c8 !important;
-}
-
-.purple-text.text-lighten-2 {
-  color: #ba68c8 !important;
-}
-
-.purple.lighten-1 {
-  background-color: #ab47bc !important;
-}
-
-.purple-text.text-lighten-1 {
-  color: #ab47bc !important;
-}
-
-.purple.darken-1 {
-  background-color: #8e24aa !important;
-}
-
-.purple-text.text-darken-1 {
-  color: #8e24aa !important;
-}
-
-.purple.darken-2 {
-  background-color: #7b1fa2 !important;
-}
-
-.purple-text.text-darken-2 {
-  color: #7b1fa2 !important;
-}
-
-.purple.darken-3 {
-  background-color: #6a1b9a !important;
-}
-
-.purple-text.text-darken-3 {
-  color: #6a1b9a !important;
-}
-
-.purple.darken-4 {
-  background-color: #4a148c !important;
-}
-
-.purple-text.text-darken-4 {
-  color: #4a148c !important;
-}
-
-.purple.accent-1 {
-  background-color: #ea80fc !important;
-}
-
-.purple-text.text-accent-1 {
-  color: #ea80fc !important;
-}
-
-.purple.accent-2 {
-  background-color: #e040fb !important;
-}
-
-.purple-text.text-accent-2 {
-  color: #e040fb !important;
-}
-
-.purple.accent-3 {
-  background-color: #d500f9 !important;
-}
-
-.purple-text.text-accent-3 {
-  color: #d500f9 !important;
-}
-
-.purple.accent-4 {
-  background-color: #aa00ff !important;
-}
-
-.purple-text.text-accent-4 {
-  color: #aa00ff !important;
-}
-
-.deep-purple {
-  background-color: #673ab7 !important;
-}
-
-.deep-purple-text {
-  color: #673ab7 !important;
-}
-
-.deep-purple.lighten-5 {
-  background-color: #ede7f6 !important;
-}
-
-.deep-purple-text.text-lighten-5 {
-  color: #ede7f6 !important;
-}
-
-.deep-purple.lighten-4 {
-  background-color: #d1c4e9 !important;
-}
-
-.deep-purple-text.text-lighten-4 {
-  color: #d1c4e9 !important;
-}
-
-.deep-purple.lighten-3 {
-  background-color: #b39ddb !important;
-}
-
-.deep-purple-text.text-lighten-3 {
-  color: #b39ddb !important;
-}
-
-.deep-purple.lighten-2 {
-  background-color: #9575cd !important;
-}
-
-.deep-purple-text.text-lighten-2 {
-  color: #9575cd !important;
-}
-
-.deep-purple.lighten-1 {
-  background-color: #7e57c2 !important;
-}
-
-.deep-purple-text.text-lighten-1 {
-  color: #7e57c2 !important;
-}
-
-.deep-purple.darken-1 {
-  background-color: #5e35b1 !important;
-}
-
-.deep-purple-text.text-darken-1 {
-  color: #5e35b1 !important;
-}
-
-.deep-purple.darken-2 {
-  background-color: #512da8 !important;
-}
-
-.deep-purple-text.text-darken-2 {
-  color: #512da8 !important;
-}
-
-.deep-purple.darken-3 {
-  background-color: #4527a0 !important;
-}
-
-.deep-purple-text.text-darken-3 {
-  color: #4527a0 !important;
-}
-
-.deep-purple.darken-4 {
-  background-color: #311b92 !important;
-}
-
-.deep-purple-text.text-darken-4 {
-  color: #311b92 !important;
-}
-
-.deep-purple.accent-1 {
-  background-color: #b388ff !important;
-}
-
-.deep-purple-text.text-accent-1 {
-  color: #b388ff !important;
-}
-
-.deep-purple.accent-2 {
-  background-color: #7c4dff !important;
-}
-
-.deep-purple-text.text-accent-2 {
-  color: #7c4dff !important;
-}
-
-.deep-purple.accent-3 {
-  background-color: #651fff !important;
-}
-
-.deep-purple-text.text-accent-3 {
-  color: #651fff !important;
-}
-
-.deep-purple.accent-4 {
-  background-color: #6200ea !important;
-}
-
-.deep-purple-text.text-accent-4 {
-  color: #6200ea !important;
-}
-
-.indigo {
-  background-color: #3f51b5 !important;
-}
-
-.indigo-text {
-  color: #3f51b5 !important;
-}
-
-.indigo.lighten-5 {
-  background-color: #e8eaf6 !important;
-}
-
-.indigo-text.text-lighten-5 {
-  color: #e8eaf6 !important;
-}
-
-.indigo.lighten-4 {
-  background-color: #c5cae9 !important;
-}
-
-.indigo-text.text-lighten-4 {
-  color: #c5cae9 !important;
-}
-
-.indigo.lighten-3 {
-  background-color: #9fa8da !important;
-}
-
-.indigo-text.text-lighten-3 {
-  color: #9fa8da !important;
-}
-
-.indigo.lighten-2 {
-  background-color: #7986cb !important;
-}
-
-.indigo-text.text-lighten-2 {
-  color: #7986cb !important;
-}
-
-.indigo.lighten-1 {
-  background-color: #5c6bc0 !important;
-}
-
-.indigo-text.text-lighten-1 {
-  color: #5c6bc0 !important;
-}
-
-.indigo.darken-1 {
-  background-color: #3949ab !important;
-}
-
-.indigo-text.text-darken-1 {
-  color: #3949ab !important;
-}
-
-.indigo.darken-2 {
-  background-color: #303f9f !important;
-}
-
-.indigo-text.text-darken-2 {
-  color: #303f9f !important;
-}
-
-.indigo.darken-3 {
-  background-color: #283593 !important;
-}
-
-.indigo-text.text-darken-3 {
-  color: #283593 !important;
-}
-
-.indigo.darken-4 {
-  background-color: #1a237e !important;
-}
-
-.indigo-text.text-darken-4 {
-  color: #1a237e !important;
-}
-
-.indigo.accent-1 {
-  background-color: #8c9eff !important;
-}
-
-.indigo-text.text-accent-1 {
-  color: #8c9eff !important;
-}
-
-.indigo.accent-2 {
-  background-color: #536dfe !important;
-}
-
-.indigo-text.text-accent-2 {
-  color: #536dfe !important;
-}
-
-.indigo.accent-3 {
-  background-color: #3d5afe !important;
-}
-
-.indigo-text.text-accent-3 {
-  color: #3d5afe !important;
-}
-
-.indigo.accent-4 {
-  background-color: #304ffe !important;
-}
-
-.indigo-text.text-accent-4 {
-  color: #304ffe !important;
-}
-
-.blue {
-  background-color: #2196F3 !important;
-}
-
-.blue-text {
-  color: #2196F3 !important;
-}
-
-.blue.lighten-5 {
-  background-color: #E3F2FD !important;
-}
-
-.blue-text.text-lighten-5 {
-  color: #E3F2FD !important;
-}
-
-.blue.lighten-4 {
-  background-color: #BBDEFB !important;
-}
-
-.blue-text.text-lighten-4 {
-  color: #BBDEFB !important;
-}
-
-.blue.lighten-3 {
-  background-color: #90CAF9 !important;
-}
-
-.blue-text.text-lighten-3 {
-  color: #90CAF9 !important;
-}
-
-.blue.lighten-2 {
-  background-color: #64B5F6 !important;
-}
-
-.blue-text.text-lighten-2 {
-  color: #64B5F6 !important;
-}
-
-.blue.lighten-1 {
-  background-color: #42A5F5 !important;
-}
-
-.blue-text.text-lighten-1 {
-  color: #42A5F5 !important;
-}
-
-.blue.darken-1 {
-  background-color: #1E88E5 !important;
-}
-
-.blue-text.text-darken-1 {
-  color: #1E88E5 !important;
-}
-
-.blue.darken-2 {
-  background-color: #1976D2 !important;
-}
-
-.blue-text.text-darken-2 {
-  color: #1976D2 !important;
-}
-
-.blue.darken-3 {
-  background-color: #1565C0 !important;
-}
-
-.blue-text.text-darken-3 {
-  color: #1565C0 !important;
-}
-
-.blue.darken-4 {
-  background-color: #0D47A1 !important;
-}
-
-.blue-text.text-darken-4 {
-  color: #0D47A1 !important;
-}
-
-.blue.accent-1 {
-  background-color: #82B1FF !important;
-}
-
-.blue-text.text-accent-1 {
-  color: #82B1FF !important;
-}
-
-.blue.accent-2 {
-  background-color: #448AFF !important;
-}
-
-.blue-text.text-accent-2 {
-  color: #448AFF !important;
-}
-
-.blue.accent-3 {
-  background-color: #2979FF !important;
-}
-
-.blue-text.text-accent-3 {
-  color: #2979FF !important;
-}
-
-.blue.accent-4 {
-  background-color: #2962FF !important;
-}
-
-.blue-text.text-accent-4 {
-  color: #2962FF !important;
-}
-
-.light-blue {
-  background-color: #03a9f4 !important;
-}
-
-.light-blue-text {
-  color: #03a9f4 !important;
-}
-
-.light-blue.lighten-5 {
-  background-color: #e1f5fe !important;
-}
-
-.light-blue-text.text-lighten-5 {
-  color: #e1f5fe !important;
-}
-
-.light-blue.lighten-4 {
-  background-color: #b3e5fc !important;
-}
-
-.light-blue-text.text-lighten-4 {
-  color: #b3e5fc !important;
-}
-
-.light-blue.lighten-3 {
-  background-color: #81d4fa !important;
-}
-
-.light-blue-text.text-lighten-3 {
-  color: #81d4fa !important;
-}
-
-.light-blue.lighten-2 {
-  background-color: #4fc3f7 !important;
-}
-
-.light-blue-text.text-lighten-2 {
-  color: #4fc3f7 !important;
-}
-
-.light-blue.lighten-1 {
-  background-color: #29b6f6 !important;
-}
-
-.light-blue-text.text-lighten-1 {
-  color: #29b6f6 !important;
-}
-
-.light-blue.darken-1 {
-  background-color: #039be5 !important;
-}
-
-.light-blue-text.text-darken-1 {
-  color: #039be5 !important;
-}
-
-.light-blue.darken-2 {
-  background-color: #0288d1 !important;
-}
-
-.light-blue-text.text-darken-2 {
-  color: #0288d1 !important;
-}
-
-.light-blue.darken-3 {
-  background-color: #0277bd !important;
-}
-
-.light-blue-text.text-darken-3 {
-  color: #0277bd !important;
-}
-
-.light-blue.darken-4 {
-  background-color: #01579b !important;
-}
-
-.light-blue-text.text-darken-4 {
-  color: #01579b !important;
-}
-
-.light-blue.accent-1 {
-  background-color: #80d8ff !important;
-}
-
-.light-blue-text.text-accent-1 {
-  color: #80d8ff !important;
-}
-
-.light-blue.accent-2 {
-  background-color: #40c4ff !important;
-}
-
-.light-blue-text.text-accent-2 {
-  color: #40c4ff !important;
-}
-
-.light-blue.accent-3 {
-  background-color: #00b0ff !important;
-}
-
-.light-blue-text.text-accent-3 {
-  color: #00b0ff !important;
-}
-
-.light-blue.accent-4 {
-  background-color: #0091ea !important;
-}
-
-.light-blue-text.text-accent-4 {
-  color: #0091ea !important;
-}
-
-.cyan {
-  background-color: #00bcd4 !important;
-}
-
-.cyan-text {
-  color: #00bcd4 !important;
-}
-
-.cyan.lighten-5 {
-  background-color: #e0f7fa !important;
-}
-
-.cyan-text.text-lighten-5 {
-  color: #e0f7fa !important;
-}
-
-.cyan.lighten-4 {
-  background-color: #b2ebf2 !important;
-}
-
-.cyan-text.text-lighten-4 {
-  color: #b2ebf2 !important;
-}
-
-.cyan.lighten-3 {
-  background-color: #80deea !important;
-}
-
-.cyan-text.text-lighten-3 {
-  color: #80deea !important;
-}
-
-.cyan.lighten-2 {
-  background-color: #4dd0e1 !important;
-}
-
-.cyan-text.text-lighten-2 {
-  color: #4dd0e1 !important;
-}
-
-.cyan.lighten-1 {
-  background-color: #26c6da !important;
-}
-
-.cyan-text.text-lighten-1 {
-  color: #26c6da !important;
-}
-
-.cyan.darken-1 {
-  background-color: #00acc1 !important;
-}
-
-.cyan-text.text-darken-1 {
-  color: #00acc1 !important;
-}
-
-.cyan.darken-2 {
-  background-color: #0097a7 !important;
-}
-
-.cyan-text.text-darken-2 {
-  color: #0097a7 !important;
-}
-
-.cyan.darken-3 {
-  background-color: #00838f !important;
-}
-
-.cyan-text.text-darken-3 {
-  color: #00838f !important;
-}
-
-.cyan.darken-4 {
-  background-color: #006064 !important;
-}
-
-.cyan-text.text-darken-4 {
-  color: #006064 !important;
-}
-
-.cyan.accent-1 {
-  background-color: #84ffff !important;
-}
-
-.cyan-text.text-accent-1 {
-  color: #84ffff !important;
-}
-
-.cyan.accent-2 {
-  background-color: #18ffff !important;
-}
-
-.cyan-text.text-accent-2 {
-  color: #18ffff !important;
-}
-
-.cyan.accent-3 {
-  background-color: #00e5ff !important;
-}
-
-.cyan-text.text-accent-3 {
-  color: #00e5ff !important;
-}
-
-.cyan.accent-4 {
-  background-color: #00b8d4 !important;
-}
-
-.cyan-text.text-accent-4 {
-  color: #00b8d4 !important;
-}
-
-.teal {
-  background-color: #009688 !important;
-}
-
-.teal-text {
-  color: #009688 !important;
-}
-
-.teal.lighten-5 {
-  background-color: #e0f2f1 !important;
-}
-
-.teal-text.text-lighten-5 {
-  color: #e0f2f1 !important;
-}
-
-.teal.lighten-4 {
-  background-color: #b2dfdb !important;
-}
-
-.teal-text.text-lighten-4 {
-  color: #b2dfdb !important;
-}
-
-.teal.lighten-3 {
-  background-color: #80cbc4 !important;
-}
-
-.teal-text.text-lighten-3 {
-  color: #80cbc4 !important;
-}
-
-.teal.lighten-2 {
-  background-color: #4db6ac !important;
-}
-
-.teal-text.text-lighten-2 {
-  color: #4db6ac !important;
-}
-
-.teal.lighten-1 {
-  background-color: #26a69a !important;
-}
-
-.teal-text.text-lighten-1 {
-  color: #26a69a !important;
-}
-
-.teal.darken-1 {
-  background-color: #00897b !important;
-}
-
-.teal-text.text-darken-1 {
-  color: #00897b !important;
-}
-
-.teal.darken-2 {
-  background-color: #00796b !important;
-}
-
-.teal-text.text-darken-2 {
-  color: #00796b !important;
-}
-
-.teal.darken-3 {
-  background-color: #00695c !important;
-}
-
-.teal-text.text-darken-3 {
-  color: #00695c !important;
-}
-
-.teal.darken-4 {
-  background-color: #004d40 !important;
-}
-
-.teal-text.text-darken-4 {
-  color: #004d40 !important;
-}
-
-.teal.accent-1 {
-  background-color: #a7ffeb !important;
-}
-
-.teal-text.text-accent-1 {
-  color: #a7ffeb !important;
-}
-
-.teal.accent-2 {
-  background-color: #64ffda !important;
-}
-
-.teal-text.text-accent-2 {
-  color: #64ffda !important;
-}
-
-.teal.accent-3 {
-  background-color: #1de9b6 !important;
-}
-
-.teal-text.text-accent-3 {
-  color: #1de9b6 !important;
-}
-
-.teal.accent-4 {
-  background-color: #00bfa5 !important;
-}
-
-.teal-text.text-accent-4 {
-  color: #00bfa5 !important;
-}
-
-.green {
-  background-color: #4CAF50 !important;
-}
-
-.green-text {
-  color: #4CAF50 !important;
-}
-
-.green.lighten-5 {
-  background-color: #E8F5E9 !important;
-}
-
-.green-text.text-lighten-5 {
-  color: #E8F5E9 !important;
-}
-
-.green.lighten-4 {
-  background-color: #C8E6C9 !important;
-}
-
-.green-text.text-lighten-4 {
-  color: #C8E6C9 !important;
-}
-
-.green.lighten-3 {
-  background-color: #A5D6A7 !important;
-}
-
-.green-text.text-lighten-3 {
-  color: #A5D6A7 !important;
-}
-
-.green.lighten-2 {
-  background-color: #81C784 !important;
-}
-
-.green-text.text-lighten-2 {
-  color: #81C784 !important;
-}
-
-.green.lighten-1 {
-  background-color: #66BB6A !important;
-}
-
-.green-text.text-lighten-1 {
-  color: #66BB6A !important;
-}
-
-.green.darken-1 {
-  background-color: #43A047 !important;
-}
-
-.green-text.text-darken-1 {
-  color: #43A047 !important;
-}
-
-.green.darken-2 {
-  background-color: #388E3C !important;
-}
-
-.green-text.text-darken-2 {
-  color: #388E3C !important;
-}
-
-.green.darken-3 {
-  background-color: #2E7D32 !important;
-}
-
-.green-text.text-darken-3 {
-  color: #2E7D32 !important;
-}
-
-.green.darken-4 {
-  background-color: #1B5E20 !important;
-}
-
-.green-text.text-darken-4 {
-  color: #1B5E20 !important;
-}
-
-.green.accent-1 {
-  background-color: #B9F6CA !important;
-}
-
-.green-text.text-accent-1 {
-  color: #B9F6CA !important;
-}
-
-.green.accent-2 {
-  background-color: #69F0AE !important;
-}
-
-.green-text.text-accent-2 {
-  color: #69F0AE !important;
-}
-
-.green.accent-3 {
-  background-color: #00E676 !important;
-}
-
-.green-text.text-accent-3 {
-  color: #00E676 !important;
-}
-
-.green.accent-4 {
-  background-color: #00C853 !important;
-}
-
-.green-text.text-accent-4 {
-  color: #00C853 !important;
-}
-
-.light-green {
-  background-color: #8bc34a !important;
-}
-
-.light-green-text {
-  color: #8bc34a !important;
-}
-
-.light-green.lighten-5 {
-  background-color: #f1f8e9 !important;
-}
-
-.light-green-text.text-lighten-5 {
-  color: #f1f8e9 !important;
-}
-
-.light-green.lighten-4 {
-  background-color: #dcedc8 !important;
-}
-
-.light-green-text.text-lighten-4 {
-  color: #dcedc8 !important;
-}
-
-.light-green.lighten-3 {
-  background-color: #c5e1a5 !important;
-}
-
-.light-green-text.text-lighten-3 {
-  color: #c5e1a5 !important;
-}
-
-.light-green.lighten-2 {
-  background-color: #aed581 !important;
-}
-
-.light-green-text.text-lighten-2 {
-  color: #aed581 !important;
-}
-
-.light-green.lighten-1 {
-  background-color: #9ccc65 !important;
-}
-
-.light-green-text.text-lighten-1 {
-  color: #9ccc65 !important;
-}
-
-.light-green.darken-1 {
-  background-color: #7cb342 !important;
-}
-
-.light-green-text.text-darken-1 {
-  color: #7cb342 !important;
-}
-
-.light-green.darken-2 {
-  background-color: #689f38 !important;
-}
-
-.light-green-text.text-darken-2 {
-  color: #689f38 !important;
-}
-
-.light-green.darken-3 {
-  background-color: #558b2f !important;
-}
-
-.light-green-text.text-darken-3 {
-  color: #558b2f !important;
-}
-
-.light-green.darken-4 {
-  background-color: #33691e !important;
-}
-
-.light-green-text.text-darken-4 {
-  color: #33691e !important;
-}
-
-.light-green.accent-1 {
-  background-color: #ccff90 !important;
-}
-
-.light-green-text.text-accent-1 {
-  color: #ccff90 !important;
-}
-
-.light-green.accent-2 {
-  background-color: #b2ff59 !important;
-}
-
-.light-green-text.text-accent-2 {
-  color: #b2ff59 !important;
-}
-
-.light-green.accent-3 {
-  background-color: #76ff03 !important;
-}
-
-.light-green-text.text-accent-3 {
-  color: #76ff03 !important;
-}
-
-.light-green.accent-4 {
-  background-color: #64dd17 !important;
-}
-
-.light-green-text.text-accent-4 {
-  color: #64dd17 !important;
-}
-
-.lime {
-  background-color: #cddc39 !important;
-}
-
-.lime-text {
-  color: #cddc39 !important;
-}
-
-.lime.lighten-5 {
-  background-color: #f9fbe7 !important;
-}
-
-.lime-text.text-lighten-5 {
-  color: #f9fbe7 !important;
-}
-
-.lime.lighten-4 {
-  background-color: #f0f4c3 !important;
-}
-
-.lime-text.text-lighten-4 {
-  color: #f0f4c3 !important;
-}
-
-.lime.lighten-3 {
-  background-color: #e6ee9c !important;
-}
-
-.lime-text.text-lighten-3 {
-  color: #e6ee9c !important;
-}
-
-.lime.lighten-2 {
-  background-color: #dce775 !important;
-}
-
-.lime-text.text-lighten-2 {
-  color: #dce775 !important;
-}
-
-.lime.lighten-1 {
-  background-color: #d4e157 !important;
-}
-
-.lime-text.text-lighten-1 {
-  color: #d4e157 !important;
-}
-
-.lime.darken-1 {
-  background-color: #c0ca33 !important;
-}
-
-.lime-text.text-darken-1 {
-  color: #c0ca33 !important;
-}
-
-.lime.darken-2 {
-  background-color: #afb42b !important;
-}
-
-.lime-text.text-darken-2 {
-  color: #afb42b !important;
-}
-
-.lime.darken-3 {
-  background-color: #9e9d24 !important;
-}
-
-.lime-text.text-darken-3 {
-  color: #9e9d24 !important;
-}
-
-.lime.darken-4 {
-  background-color: #827717 !important;
-}
-
-.lime-text.text-darken-4 {
-  color: #827717 !important;
-}
-
-.lime.accent-1 {
-  background-color: #f4ff81 !important;
-}
-
-.lime-text.text-accent-1 {
-  color: #f4ff81 !important;
-}
-
-.lime.accent-2 {
-  background-color: #eeff41 !important;
-}
-
-.lime-text.text-accent-2 {
-  color: #eeff41 !important;
-}
-
-.lime.accent-3 {
-  background-color: #c6ff00 !important;
-}
-
-.lime-text.text-accent-3 {
-  color: #c6ff00 !important;
-}
-
-.lime.accent-4 {
-  background-color: #aeea00 !important;
-}
-
-.lime-text.text-accent-4 {
-  color: #aeea00 !important;
-}
-
-.yellow {
-  background-color: #ffeb3b !important;
-}
-
-.yellow-text {
-  color: #ffeb3b !important;
-}
-
-.yellow.lighten-5 {
-  background-color: #fffde7 !important;
-}
-
-.yellow-text.text-lighten-5 {
-  color: #fffde7 !important;
-}
-
-.yellow.lighten-4 {
-  background-color: #fff9c4 !important;
-}
-
-.yellow-text.text-lighten-4 {
-  color: #fff9c4 !important;
-}
-
-.yellow.lighten-3 {
-  background-color: #fff59d !important;
-}
-
-.yellow-text.text-lighten-3 {
-  color: #fff59d !important;
-}
-
-.yellow.lighten-2 {
-  background-color: #fff176 !important;
-}
-
-.yellow-text.text-lighten-2 {
-  color: #fff176 !important;
-}
-
-.yellow.lighten-1 {
-  background-color: #ffee58 !important;
-}
-
-.yellow-text.text-lighten-1 {
-  color: #ffee58 !important;
-}
-
-.yellow.darken-1 {
-  background-color: #fdd835 !important;
-}
-
-.yellow-text.text-darken-1 {
-  color: #fdd835 !important;
-}
-
-.yellow.darken-2 {
-  background-color: #fbc02d !important;
-}
-
-.yellow-text.text-darken-2 {
-  color: #fbc02d !important;
-}
-
-.yellow.darken-3 {
-  background-color: #f9a825 !important;
-}
-
-.yellow-text.text-darken-3 {
-  color: #f9a825 !important;
-}
-
-.yellow.darken-4 {
-  background-color: #f57f17 !important;
-}
-
-.yellow-text.text-darken-4 {
-  color: #f57f17 !important;
-}
-
-.yellow.accent-1 {
-  background-color: #ffff8d !important;
-}
-
-.yellow-text.text-accent-1 {
-  color: #ffff8d !important;
-}
-
-.yellow.accent-2 {
-  background-color: #ffff00 !important;
-}
-
-.yellow-text.text-accent-2 {
-  color: #ffff00 !important;
-}
-
-.yellow.accent-3 {
-  background-color: #ffea00 !important;
-}
-
-.yellow-text.text-accent-3 {
-  color: #ffea00 !important;
-}
-
-.yellow.accent-4 {
-  background-color: #ffd600 !important;
-}
-
-.yellow-text.text-accent-4 {
-  color: #ffd600 !important;
-}
-
-.amber {
-  background-color: #ffc107 !important;
-}
-
-.amber-text {
-  color: #ffc107 !important;
-}
-
-.amber.lighten-5 {
-  background-color: #fff8e1 !important;
-}
-
-.amber-text.text-lighten-5 {
-  color: #fff8e1 !important;
-}
-
-.amber.lighten-4 {
-  background-color: #ffecb3 !important;
-}
-
-.amber-text.text-lighten-4 {
-  color: #ffecb3 !important;
-}
-
-.amber.lighten-3 {
-  background-color: #ffe082 !important;
-}
-
-.amber-text.text-lighten-3 {
-  color: #ffe082 !important;
-}
-
-.amber.lighten-2 {
-  background-color: #ffd54f !important;
-}
-
-.amber-text.text-lighten-2 {
-  color: #ffd54f !important;
-}
-
-.amber.lighten-1 {
-  background-color: #ffca28 !important;
-}
-
-.amber-text.text-lighten-1 {
-  color: #ffca28 !important;
-}
-
-.amber.darken-1 {
-  background-color: #ffb300 !important;
-}
-
-.amber-text.text-darken-1 {
-  color: #ffb300 !important;
-}
-
-.amber.darken-2 {
-  background-color: #ffa000 !important;
-}
-
-.amber-text.text-darken-2 {
-  color: #ffa000 !important;
-}
-
-.amber.darken-3 {
-  background-color: #ff8f00 !important;
-}
-
-.amber-text.text-darken-3 {
-  color: #ff8f00 !important;
-}
-
-.amber.darken-4 {
-  background-color: #ff6f00 !important;
-}
-
-.amber-text.text-darken-4 {
-  color: #ff6f00 !important;
-}
-
-.amber.accent-1 {
-  background-color: #ffe57f !important;
-}
-
-.amber-text.text-accent-1 {
-  color: #ffe57f !important;
-}
-
-.amber.accent-2 {
-  background-color: #ffd740 !important;
-}
-
-.amber-text.text-accent-2 {
-  color: #ffd740 !important;
-}
-
-.amber.accent-3 {
-  background-color: #ffc400 !important;
-}
-
-.amber-text.text-accent-3 {
-  color: #ffc400 !important;
-}
-
-.amber.accent-4 {
-  background-color: #ffab00 !important;
-}
-
-.amber-text.text-accent-4 {
-  color: #ffab00 !important;
-}
-
-.orange {
-  background-color: #ff9800 !important;
-}
-
-.orange-text {
-  color: #ff9800 !important;
-}
-
-.orange.lighten-5 {
-  background-color: #fff3e0 !important;
-}
-
-.orange-text.text-lighten-5 {
-  color: #fff3e0 !important;
-}
-
-.orange.lighten-4 {
-  background-color: #ffe0b2 !important;
-}
-
-.orange-text.text-lighten-4 {
-  color: #ffe0b2 !important;
-}
-
-.orange.lighten-3 {
-  background-color: #ffcc80 !important;
-}
-
-.orange-text.text-lighten-3 {
-  color: #ffcc80 !important;
-}
-
-.orange.lighten-2 {
-  background-color: #ffb74d !important;
-}
-
-.orange-text.text-lighten-2 {
-  color: #ffb74d !important;
-}
-
-.orange.lighten-1 {
-  background-color: #ffa726 !important;
-}
-
-.orange-text.text-lighten-1 {
-  color: #ffa726 !important;
-}
-
-.orange.darken-1 {
-  background-color: #fb8c00 !important;
-}
-
-.orange-text.text-darken-1 {
-  color: #fb8c00 !important;
-}
-
-.orange.darken-2 {
-  background-color: #f57c00 !important;
-}
-
-.orange-text.text-darken-2 {
-  color: #f57c00 !important;
-}
-
-.orange.darken-3 {
-  background-color: #ef6c00 !important;
-}
-
-.orange-text.text-darken-3 {
-  color: #ef6c00 !important;
-}
-
-.orange.darken-4 {
-  background-color: #e65100 !important;
-}
-
-.orange-text.text-darken-4 {
-  color: #e65100 !important;
-}
-
-.orange.accent-1 {
-  background-color: #ffd180 !important;
-}
-
-.orange-text.text-accent-1 {
-  color: #ffd180 !important;
-}
-
-.orange.accent-2 {
-  background-color: #ffab40 !important;
-}
-
-.orange-text.text-accent-2 {
-  color: #ffab40 !important;
-}
-
-.orange.accent-3 {
-  background-color: #ff9100 !important;
-}
-
-.orange-text.text-accent-3 {
-  color: #ff9100 !important;
-}
-
-.orange.accent-4 {
-  background-color: #ff6d00 !important;
-}
-
-.orange-text.text-accent-4 {
-  color: #ff6d00 !important;
-}
-
-.deep-orange {
-  background-color: #ff5722 !important;
-}
-
-.deep-orange-text {
-  color: #ff5722 !important;
-}
-
-.deep-orange.lighten-5 {
-  background-color: #fbe9e7 !important;
-}
-
-.deep-orange-text.text-lighten-5 {
-  color: #fbe9e7 !important;
-}
-
-.deep-orange.lighten-4 {
-  background-color: #ffccbc !important;
-}
-
-.deep-orange-text.text-lighten-4 {
-  color: #ffccbc !important;
-}
-
-.deep-orange.lighten-3 {
-  background-color: #ffab91 !important;
-}
-
-.deep-orange-text.text-lighten-3 {
-  color: #ffab91 !important;
-}
-
-.deep-orange.lighten-2 {
-  background-color: #ff8a65 !important;
-}
-
-.deep-orange-text.text-lighten-2 {
-  color: #ff8a65 !important;
-}
-
-.deep-orange.lighten-1 {
-  background-color: #ff7043 !important;
-}
-
-.deep-orange-text.text-lighten-1 {
-  color: #ff7043 !important;
-}
-
-.deep-orange.darken-1 {
-  background-color: #f4511e !important;
-}
-
-.deep-orange-text.text-darken-1 {
-  color: #f4511e !important;
-}
-
-.deep-orange.darken-2 {
-  background-color: #e64a19 !important;
-}
-
-.deep-orange-text.text-darken-2 {
-  color: #e64a19 !important;
-}
-
-.deep-orange.darken-3 {
-  background-color: #d84315 !important;
-}
-
-.deep-orange-text.text-darken-3 {
-  color: #d84315 !important;
-}
-
-.deep-orange.darken-4 {
-  background-color: #bf360c !important;
-}
-
-.deep-orange-text.text-darken-4 {
-  color: #bf360c !important;
-}
-
-.deep-orange.accent-1 {
-  background-color: #ff9e80 !important;
-}
-
-.deep-orange-text.text-accent-1 {
-  color: #ff9e80 !important;
-}
-
-.deep-orange.accent-2 {
-  background-color: #ff6e40 !important;
-}
-
-.deep-orange-text.text-accent-2 {
-  color: #ff6e40 !important;
-}
-
-.deep-orange.accent-3 {
-  background-color: #ff3d00 !important;
-}
-
-.deep-orange-text.text-accent-3 {
-  color: #ff3d00 !important;
-}
-
-.deep-orange.accent-4 {
-  background-color: #dd2c00 !important;
-}
-
-.deep-orange-text.text-accent-4 {
-  color: #dd2c00 !important;
-}
-
-.brown {
-  background-color: #795548 !important;
-}
-
-.brown-text {
-  color: #795548 !important;
-}
-
-.brown.lighten-5 {
-  background-color: #efebe9 !important;
-}
-
-.brown-text.text-lighten-5 {
-  color: #efebe9 !important;
-}
-
-.brown.lighten-4 {
-  background-color: #d7ccc8 !important;
-}
-
-.brown-text.text-lighten-4 {
-  color: #d7ccc8 !important;
-}
-
-.brown.lighten-3 {
-  background-color: #bcaaa4 !important;
-}
-
-.brown-text.text-lighten-3 {
-  color: #bcaaa4 !important;
-}
-
-.brown.lighten-2 {
-  background-color: #a1887f !important;
-}
-
-.brown-text.text-lighten-2 {
-  color: #a1887f !important;
-}
-
-.brown.lighten-1 {
-  background-color: #8d6e63 !important;
-}
-
-.brown-text.text-lighten-1 {
-  color: #8d6e63 !important;
-}
-
-.brown.darken-1 {
-  background-color: #6d4c41 !important;
-}
-
-.brown-text.text-darken-1 {
-  color: #6d4c41 !important;
-}
-
-.brown.darken-2 {
-  background-color: #5d4037 !important;
-}
-
-.brown-text.text-darken-2 {
-  color: #5d4037 !important;
-}
-
-.brown.darken-3 {
-  background-color: #4e342e !important;
-}
-
-.brown-text.text-darken-3 {
-  color: #4e342e !important;
-}
-
-.brown.darken-4 {
-  background-color: #3e2723 !important;
-}
-
-.brown-text.text-darken-4 {
-  color: #3e2723 !important;
-}
-
-.blue-grey {
-  background-color: #607d8b !important;
-}
-
-.blue-grey-text {
-  color: #607d8b !important;
-}
-
-.blue-grey.lighten-5 {
-  background-color: #eceff1 !important;
-}
-
-.blue-grey-text.text-lighten-5 {
-  color: #eceff1 !important;
-}
-
-.blue-grey.lighten-4 {
-  background-color: #cfd8dc !important;
-}
-
-.blue-grey-text.text-lighten-4 {
-  color: #cfd8dc !important;
-}
-
-.blue-grey.lighten-3 {
-  background-color: #b0bec5 !important;
-}
-
-.blue-grey-text.text-lighten-3 {
-  color: #b0bec5 !important;
-}
-
-.blue-grey.lighten-2 {
-  background-color: #90a4ae !important;
-}
-
-.blue-grey-text.text-lighten-2 {
-  color: #90a4ae !important;
-}
-
-.blue-grey.lighten-1 {
-  background-color: #78909c !important;
-}
-
-.blue-grey-text.text-lighten-1 {
-  color: #78909c !important;
-}
-
-.blue-grey.darken-1 {
-  background-color: #546e7a !important;
-}
-
-.blue-grey-text.text-darken-1 {
-  color: #546e7a !important;
-}
-
-.blue-grey.darken-2 {
-  background-color: #455a64 !important;
-}
-
-.blue-grey-text.text-darken-2 {
-  color: #455a64 !important;
-}
-
-.blue-grey.darken-3 {
-  background-color: #37474f !important;
-}
-
-.blue-grey-text.text-darken-3 {
-  color: #37474f !important;
-}
-
-.blue-grey.darken-4 {
-  background-color: #263238 !important;
-}
-
-.blue-grey-text.text-darken-4 {
-  color: #263238 !important;
-}
-
-.grey {
-  background-color: #9e9e9e !important;
-}
-
-.grey-text {
-  color: #9e9e9e !important;
-}
-
-.grey.lighten-5 {
-  background-color: #fafafa !important;
-}
-
-.grey-text.text-lighten-5 {
-  color: #fafafa !important;
-}
-
-.grey.lighten-4 {
-  background-color: #f5f5f5 !important;
-}
-
-.grey-text.text-lighten-4 {
-  color: #f5f5f5 !important;
-}
-
-.grey.lighten-3 {
-  background-color: #eeeeee !important;
-}
-
-.grey-text.text-lighten-3 {
-  color: #eeeeee !important;
-}
-
-.grey.lighten-2 {
-  background-color: #e0e0e0 !important;
-}
-
-.grey-text.text-lighten-2 {
-  color: #e0e0e0 !important;
-}
-
-.grey.lighten-1 {
-  background-color: #bdbdbd !important;
-}
-
-.grey-text.text-lighten-1 {
-  color: #bdbdbd !important;
-}
-
-.grey.darken-1 {
-  background-color: #757575 !important;
-}
-
-.grey-text.text-darken-1 {
-  color: #757575 !important;
-}
-
-.grey.darken-2 {
-  background-color: #616161 !important;
-}
-
-.grey-text.text-darken-2 {
-  color: #616161 !important;
-}
-
-.grey.darken-3 {
-  background-color: #424242 !important;
-}
-
-.grey-text.text-darken-3 {
-  color: #424242 !important;
-}
-
-.grey.darken-4 {
-  background-color: #212121 !important;
-}
-
-.grey-text.text-darken-4 {
-  color: #212121 !important;
-}
-
-.black {
-  background-color: #000000 !important;
-}
-
-.black-text {
-  color: #000000 !important;
-}
-
-.white {
-  background-color: #FFFFFF !important;
-}
-
-.white-text {
-  color: #FFFFFF !important;
-}
-
-.transparent {
-  background-color: transparent !important;
-}
-
-.transparent-text {
-  color: transparent !important;
-}
-
-/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
-/**
- * 1. Set default font family to sans-serif.
- * 2. Prevent iOS and IE text size adjust after device orientation change,
- *    without disabling user zoom.
- */
-html {
-  font-family: sans-serif;
-  /* 1 */
-  -ms-text-size-adjust: 100%;
-  /* 2 */
-  -webkit-text-size-adjust: 100%;
-  /* 2 */
-}
-
-/**
- * Remove default margin.
- */
-body {
-  margin: 0;
-}
-
-/* HTML5 display definitions
-   ========================================================================== */
-/**
- * Correct `block` display not defined for any HTML5 element in IE 8/9.
- * Correct `block` display not defined for `details` or `summary` in IE 10/11
- * and Firefox.
- * Correct `block` display not defined for `main` in IE 11.
- */
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-menu,
-nav,
-section,
-summary {
-  display: block;
-}
-
-/**
- * 1. Correct `inline-block` display not defined in IE 8/9.
- * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
- */
-audio,
-canvas,
-progress,
-video {
-  display: inline-block;
-  /* 1 */
-  vertical-align: baseline;
-  /* 2 */
-}
-
-/**
- * Prevent modern browsers from displaying `audio` without controls.
- * Remove excess height in iOS 5 devices.
- */
-audio:not([controls]) {
-  display: none;
-  height: 0;
-}
-
-/**
- * Address `[hidden]` styling not present in IE 8/9/10.
- * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
- */
-[hidden],
-template {
-  display: none;
-}
-
-/* Links
-   ========================================================================== */
-/**
- * Remove the gray background color from active links in IE 10.
- */
-a {
-  background-color: transparent;
-}
-
-/**
- * Improve readability of focused elements when they are also in an
- * active/hover state.
- */
-a:active,
-a:hover {
-  outline: 0;
-}
-
-/* Text-level semantics
-   ========================================================================== */
-/**
- * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
- */
-abbr[title] {
-  border-bottom: 1px dotted;
-}
-
-/**
- * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
- */
-b,
-strong {
-  font-weight: bold;
-}
-
-/**
- * Address styling not present in Safari and Chrome.
- */
-dfn {
-  font-style: italic;
-}
-
-/**
- * Address variable `h1` font-size and margin within `section` and `article`
- * contexts in Firefox 4+, Safari, and Chrome.
- */
-h1 {
-  font-size: 2em;
-  margin: 0.67em 0;
-}
-
-/**
- * Address styling not present in IE 8/9.
- */
-mark {
-  background: #ff0;
-  color: #000;
-}
-
-/**
- * Address inconsistent and variable font size in all browsers.
- */
-small {
-  font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` affecting `line-height` in all browsers.
- */
-sub,
-sup {
-  font-size: 75%;
-  line-height: 0;
-  position: relative;
-  vertical-align: baseline;
-}
-
-sup {
-  top: -0.5em;
-}
-
-sub {
-  bottom: -0.25em;
-}
-
-/* Embedded content
-   ========================================================================== */
-/**
- * Remove border when inside `a` element in IE 8/9/10.
- */
-img {
-  border: 0;
-}
-
-/**
- * Correct overflow not hidden in IE 9/10/11.
- */
-svg:not(:root) {
-  overflow: hidden;
-}
-
-/* Grouping content
-   ========================================================================== */
-/**
- * Address margin not present in IE 8/9 and Safari.
- */
-figure {
-  margin: 1em 40px;
-}
-
-/**
- * Address differences between Firefox and other browsers.
- */
-hr {
-  box-sizing: content-box;
-  height: 0;
-}
-
-/**
- * Contain overflow in all browsers.
- */
-pre {
-  overflow: auto;
-}
-
-/**
- * Address odd `em`-unit font size rendering in all browsers.
- */
-code,
-kbd,
-pre,
-samp {
-  font-family: monospace, monospace;
-  font-size: 1em;
-}
-
-/* Forms
-   ========================================================================== */
-/**
- * Known limitation: by default, Chrome and Safari on OS X allow very limited
- * styling of `select`, unless a `border` property is set.
- */
-/**
- * 1. Correct color not being inherited.
- *    Known issue: affects color of disabled elements.
- * 2. Correct font properties not being inherited.
- * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
- */
-button,
-input,
-optgroup,
-select,
-textarea {
-  color: inherit;
-  /* 1 */
-  font: inherit;
-  /* 2 */
-  margin: 0;
-  /* 3 */
-}
-
-/**
- * Address `overflow` set to `hidden` in IE 8/9/10/11.
- */
-button {
-  overflow: visible;
-}
-
-/**
- * Address inconsistent `text-transform` inheritance for `button` and `select`.
- * All other form control elements do not inherit `text-transform` values.
- * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
- * Correct `select` style inheritance in Firefox.
- */
-button,
-select {
-  text-transform: none;
-}
-
-/**
- * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
- *    and `video` controls.
- * 2. Correct inability to style clickable `input` types in iOS.
- * 3. Improve usability and consistency of cursor style between image-type
- *    `input` and others.
- */
-button,
-html input[type="button"],
-input[type="reset"],
-input[type="submit"] {
-  -webkit-appearance: button;
-  /* 2 */
-  cursor: pointer;
-  /* 3 */
-}
-
-/**
- * Re-set default cursor for disabled elements.
- */
-button[disabled],
-html input[disabled] {
-  cursor: default;
-}
-
-/**
- * Remove inner padding and border in Firefox 4+.
- */
-button::-moz-focus-inner,
-input::-moz-focus-inner {
-  border: 0;
-  padding: 0;
-}
-
-/**
- * Address Firefox 4+ setting `line-height` on `input` using `!important` in
- * the UA stylesheet.
- */
-input {
-  line-height: normal;
-}
-
-/**
- * It's recommended that you don't attempt to style these elements.
- * Firefox's implementation doesn't respect box-sizing, padding, or width.
- *
- * 1. Address box sizing set to `content-box` in IE 8/9/10.
- * 2. Remove excess padding in IE 8/9/10.
- */
-input[type="checkbox"],
-input[type="radio"] {
-  box-sizing: border-box;
-  /* 1 */
-  padding: 0;
-  /* 2 */
-}
-
-/**
- * Fix the cursor style for Chrome's increment/decrement buttons. For certain
- * `font-size` values of the `input`, it causes the cursor style of the
- * decrement button to change from `default` to `text`.
- */
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
-  height: auto;
-}
-
-/**
- * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
- * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
- */
-input[type="search"] {
-  -webkit-appearance: textfield;
-  /* 1 */
-  box-sizing: content-box;
-  /* 2 */
-}
-
-/**
- * Remove inner padding and search cancel button in Safari and Chrome on OS X.
- * Safari (but not Chrome) clips the cancel button when the search input has
- * padding (and `textfield` appearance).
- */
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
-  -webkit-appearance: none;
-}
-
-/**
- * Define consistent border, margin, and padding.
- */
-fieldset {
-  border: 1px solid #c0c0c0;
-  margin: 0 2px;
-  padding: 0.35em 0.625em 0.75em;
-}
-
-/**
- * 1. Correct `color` not being inherited in IE 8/9/10/11.
- * 2. Remove padding so people aren't caught out if they zero out fieldsets.
- */
-legend {
-  border: 0;
-  /* 1 */
-  padding: 0;
-  /* 2 */
-}
-
-/**
- * Remove default vertical scrollbar in IE 8/9/10/11.
- */
-textarea {
-  overflow: auto;
-}
-
-/**
- * Don't inherit the `font-weight` (applied by a rule above).
- * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
- */
-optgroup {
-  font-weight: bold;
-}
-
-/* Tables
-   ========================================================================== */
-/**
- * Remove most spacing between table cells.
- */
-table {
-  border-collapse: collapse;
-  border-spacing: 0;
-}
-
-td,
-th {
-  padding: 0;
-}
-
-html {
-  box-sizing: border-box;
-}
-
-*, *:before, *:after {
-  box-sizing: inherit;
-}
-
-ul:not(.browser-default) {
-  padding-left: 0;
-  list-style-type: none;
-}
-
-ul:not(.browser-default) li {
-  list-style-type: none;
-}
-
-a {
-  color: #039be5;
-  text-decoration: none;
-  -webkit-tap-highlight-color: transparent;
-}
-
-.valign-wrapper {
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-  -webkit-align-items: center;
-      -ms-flex-align: center;
-          align-items: center;
-}
-
-.valign-wrapper .valign {
-  display: block;
-}
-
-.clearfix {
-  clear: both;
-}
-
-.z-depth-0 {
-  box-shadow: none !important;
-}
-
-.z-depth-1, nav, .card-panel, .card, .toast, .btn, .btn-large, .btn-floating, .dropdown-content, .collapsible, .side-nav {
-  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
-}
-
-.z-depth-1-half, .btn:hover, .btn-large:hover, .btn-floating:hover {
-  box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -1px rgba(0, 0, 0, 0.2);
-}
-
-.z-depth-2 {
-  box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
-}
-
-.z-depth-3 {
-  box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.3);
-}
-
-.z-depth-4, .modal {
-  box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.3);
-}
-
-.z-depth-5 {
-  box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.3);
-}
-
-.hoverable {
-  transition: box-shadow .25s;
-  box-shadow: 0;
-}
-
-.hoverable:hover {
-  transition: box-shadow .25s;
-  box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
-}
-
-.divider {
-  height: 1px;
-  overflow: hidden;
-  background-color: #e0e0e0;
-}
-
-blockquote {
-  margin: 20px 0;
-  padding-left: 1.5rem;
-  border-left: 5px solid #ee6e73;
-}
-
-i {
-  line-height: inherit;
-}
-
-i.left {
-  float: left;
-  margin-right: 15px;
-}
-
-i.right {
-  float: right;
-  margin-left: 15px;
-}
-
-i.tiny {
-  font-size: 1rem;
-}
-
-i.small {
-  font-size: 2rem;
-}
-
-i.medium {
-  font-size: 4rem;
-}
-
-i.large {
-  font-size: 6rem;
-}
-
-img.responsive-img,
-video.responsive-video {
-  max-width: 100%;
-  height: auto;
-}
-
-.pagination li {
-  display: inline-block;
-  border-radius: 2px;
-  text-align: center;
-  vertical-align: top;
-  height: 30px;
-}
-
-.pagination li a {
-  color: #444;
-  display: inline-block;
-  font-size: 1.2rem;
-  padding: 0 10px;
-  line-height: 30px;
-}
-
-.pagination li.active a {
-  color: #fff;
-}
-
-.pagination li.active {
-  background-color: #ee6e73;
-}
-
-.pagination li.disabled a {
-  cursor: default;
-  color: #999;
-}
-
-.pagination li i {
-  font-size: 2rem;
-}
-
-.pagination li.pages ul li {
-  display: inline-block;
-  float: none;
-}
-
-@media only screen and (max-width: 992px) {
-  .pagination {
-    width: 100%;
-  }
-  .pagination li.prev,
-  .pagination li.next {
-    width: 10%;
-  }
-  .pagination li.pages {
-    width: 80%;
-    overflow: hidden;
-    white-space: nowrap;
-  }
-}
-
-.breadcrumb {
-  font-size: 18px;
-  color: rgba(255, 255, 255, 0.7);
-}
-
-.breadcrumb i,
-.breadcrumb [class^="mdi-"], .breadcrumb [class*="mdi-"],
-.breadcrumb i.material-icons {
-  display: inline-block;
-  float: left;
-  font-size: 24px;
-}
-
-.breadcrumb:before {
-  content: '\E5CC';
-  color: rgba(255, 255, 255, 0.7);
-  vertical-align: top;
-  display: inline-block;
-  font-family: 'Material Icons';
-  font-weight: normal;
-  font-style: normal;
-  font-size: 25px;
-  margin: 0 10px 0 8px;
-  -webkit-font-smoothing: antialiased;
-}
-
-.breadcrumb:first-child:before {
-  display: none;
-}
-
-.breadcrumb:last-child {
-  color: #fff;
-}
-
-.parallax-container {
-  position: relative;
-  overflow: hidden;
-  height: 500px;
-}
-
-.parallax {
-  position: absolute;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  z-index: -1;
-}
-
-.parallax img {
-  display: none;
-  position: absolute;
-  left: 50%;
-  bottom: 0;
-  min-width: 100%;
-  min-height: 100%;
-  -webkit-transform: translate3d(0, 0, 0);
-  transform: translate3d(0, 0, 0);
-  -webkit-transform: translateX(-50%);
-          transform: translateX(-50%);
-}
-
-.pin-top, .pin-bottom {
-  position: relative;
-}
-
-.pinned {
-  position: fixed !important;
-}
-
-/*********************
-  Transition Classes
-**********************/
-ul.staggered-list li {
-  opacity: 0;
-}
-
-.fade-in {
-  opacity: 0;
-  -webkit-transform-origin: 0 50%;
-          transform-origin: 0 50%;
-}
-
-/*********************
-  Media Query Classes
-**********************/
-@media only screen and (max-width: 600px) {
-  .hide-on-small-only, .hide-on-small-and-down {
-    display: none !important;
-  }
-}
-
-@media only screen and (max-width: 992px) {
-  .hide-on-med-and-down {
-    display: none !important;
-  }
-}
-
-@media only screen and (min-width: 601px) {
-  .hide-on-med-and-up {
-    display: none !important;
-  }
-}
-
-@media only screen and (min-width: 600px) and (max-width: 992px) {
-  .hide-on-med-only {
-    display: none !important;
-  }
-}
-
-@media only screen and (min-width: 993px) {
-  .hide-on-large-only {
-    display: none !important;
-  }
-}
-
-@media only screen and (min-width: 993px) {
-  .show-on-large {
-    display: block !important;
-  }
-}
-
-@media only screen and (min-width: 600px) and (max-width: 992px) {
-  .show-on-medium {
-    display: block !important;
-  }
-}
-
-@media only screen and (max-width: 600px) {
-  .show-on-small {
-    display: block !important;
-  }
-}
-
-@media only screen and (min-width: 601px) {
-  .show-on-medium-and-up {
-    display: block !important;
-  }
-}
-
-@media only screen and (max-width: 992px) {
-  .show-on-medium-and-down {
-    display: block !important;
-  }
-}
-
-@media only screen and (max-width: 600px) {
-  .center-on-small-only {
-    text-align: center;
-  }
-}
-
-footer.page-footer {
-  padding-top: 20px;
-  background-color: #ee6e73;
-}
-
-footer.page-footer .footer-copyright {
-  overflow: hidden;
-  min-height: 50px;
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-  -webkit-align-items: center;
-      -ms-flex-align: center;
-          align-items: center;
-  padding: 10px 0px;
-  color: rgba(255, 255, 255, 0.8);
-  background-color: rgba(51, 51, 51, 0.08);
-}
-
-table, th, td {
-  border: none;
-}
-
-table {
-  width: 100%;
-  display: table;
-}
-
-table.bordered > thead > tr,
-table.bordered > tbody > tr {
-  border-bottom: 1px solid #d0d0d0;
-}
-
-table.striped > tbody > tr:nth-child(odd) {
-  background-color: #f2f2f2;
-}
-
-table.striped > tbody > tr > td {
-  border-radius: 0;
-}
-
-table.highlight > tbody > tr {
-  transition: background-color .25s ease;
-}
-
-table.highlight > tbody > tr:hover {
-  background-color: #f2f2f2;
-}
-
-table.centered thead tr th, table.centered tbody tr td {
-  text-align: center;
-}
-
-thead {
-  border-bottom: 1px solid #d0d0d0;
-}
-
-td, th {
-  padding: 15px 5px;
-  display: table-cell;
-  text-align: left;
-  vertical-align: middle;
-  border-radius: 2px;
-}
-
-@media only screen and (max-width: 992px) {
-  table.responsive-table {
-    width: 100%;
-    border-collapse: collapse;
-    border-spacing: 0;
-    display: block;
-    position: relative;
-    /* sort out borders */
-  }
-  table.responsive-table td:empty:before {
-    content: '\00a0';
-  }
-  table.responsive-table th,
-  table.responsive-table td {
-    margin: 0;
-    vertical-align: top;
-  }
-  table.responsive-table th {
-    text-align: left;
-  }
-  table.responsive-table thead {
-    display: block;
-    float: left;
-  }
-  table.responsive-table thead tr {
-    display: block;
-    padding: 0 10px 0 0;
-  }
-  table.responsive-table thead tr th::before {
-    content: "\00a0";
-  }
-  table.responsive-table tbody {
-    display: block;
-    width: auto;
-    position: relative;
-    overflow-x: auto;
-    white-space: nowrap;
-  }
-  table.responsive-table tbody tr {
-    display: inline-block;
-    vertical-align: top;
-  }
-  table.responsive-table th {
-    display: block;
-    text-align: right;
-  }
-  table.responsive-table td {
-    display: block;
-    min-height: 1.25em;
-    text-align: left;
-  }
-  table.responsive-table tr {
-    padding: 0 10px;
-  }
-  table.responsive-table thead {
-    border: 0;
-    border-right: 1px solid #d0d0d0;
-  }
-  table.responsive-table.bordered th {
-    border-bottom: 0;
-    border-left: 0;
-  }
-  table.responsive-table.bordered td {
-    border-left: 0;
-    border-right: 0;
-    border-bottom: 0;
-  }
-  table.responsive-table.bordered tr {
-    border: 0;
-  }
-  table.responsive-table.bordered tbody tr {
-    border-right: 1px solid #d0d0d0;
-  }
-}
-
-.collection {
-  margin: 0.5rem 0 1rem 0;
-  border: 1px solid #e0e0e0;
-  border-radius: 2px;
-  overflow: hidden;
-  position: relative;
-}
-
-.collection .collection-item {
-  background-color: #fff;
-  line-height: 1.5rem;
-  padding: 10px 20px;
-  margin: 0;
-  border-bottom: 1px solid #e0e0e0;
-}
-
-.collection .collection-item.avatar {
-  min-height: 84px;
-  padding-left: 72px;
-  position: relative;
-}
-
-.collection .collection-item.avatar .circle {
-  position: absolute;
-  width: 42px;
-  height: 42px;
-  overflow: hidden;
-  left: 15px;
-  display: inline-block;
-  vertical-align: middle;
-}
-
-.collection .collection-item.avatar i.circle {
-  font-size: 18px;
-  line-height: 42px;
-  color: #fff;
-  background-color: #999;
-  text-align: center;
-}
-
-.collection .collection-item.avatar .title {
-  font-size: 16px;
-}
-
-.collection .collection-item.avatar p {
-  margin: 0;
-}
-
-.collection .collection-item.avatar .secondary-content {
-  position: absolute;
-  top: 16px;
-  right: 16px;
-}
-
-.collection .collection-item:last-child {
-  border-bottom: none;
-}
-
-.collection .collection-item.active {
-  background-color: #26a69a;
-  color: #eafaf9;
-}
-
-.collection .collection-item.active .secondary-content {
-  color: #fff;
-}
-
-.collection a.collection-item {
-  display: block;
-  transition: .25s;
-  color: #26a69a;
-}
-
-.collection a.collection-item:not(.active):hover {
-  background-color: #ddd;
-}
-
-.collection.with-header .collection-header {
-  background-color: #fff;
-  border-bottom: 1px solid #e0e0e0;
-  padding: 10px 20px;
-}
-
-.collection.with-header .collection-item {
-  padding-left: 30px;
-}
-
-.collection.with-header .collection-item.avatar {
-  padding-left: 72px;
-}
-
-.secondary-content {
-  float: right;
-  color: #26a69a;
-}
-
-.collapsible .collection {
-  margin: 0;
-  border: none;
-}
-
-.video-container {
-  position: relative;
-  padding-bottom: 56.25%;
-  height: 0;
-  overflow: hidden;
-}
-
-.video-container iframe, .video-container object, .video-container embed {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-}
-
-.progress {
-  position: relative;
-  height: 4px;
-  display: block;
-  width: 100%;
-  background-color: #acece6;
-  border-radius: 2px;
-  margin: 0.5rem 0 1rem 0;
-  overflow: hidden;
-}
-
-.progress .determinate {
-  position: absolute;
-  top: 0;
-  left: 0;
-  bottom: 0;
-  background-color: #26a69a;
-  transition: width .3s linear;
-}
-
-.progress .indeterminate {
-  background-color: #26a69a;
-}
-
-.progress .indeterminate:before {
-  content: '';
-  position: absolute;
-  background-color: inherit;
-  top: 0;
-  left: 0;
-  bottom: 0;
-  will-change: left, right;
-  -webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
-          animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
-}
-
-.progress .indeterminate:after {
-  content: '';
-  position: absolute;
-  background-color: inherit;
-  top: 0;
-  left: 0;
-  bottom: 0;
-  will-change: left, right;
-  -webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
-          animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
-  -webkit-animation-delay: 1.15s;
-          animation-delay: 1.15s;
-}
-
-@-webkit-keyframes indeterminate {
-  0% {
-    left: -35%;
-    right: 100%;
-  }
-  60% {
-    left: 100%;
-    right: -90%;
-  }
-  100% {
-    left: 100%;
-    right: -90%;
-  }
-}
-
-@keyframes indeterminate {
-  0% {
-    left: -35%;
-    right: 100%;
-  }
-  60% {
-    left: 100%;
-    right: -90%;
-  }
-  100% {
-    left: 100%;
-    right: -90%;
-  }
-}
-
-@-webkit-keyframes indeterminate-short {
-  0% {
-    left: -200%;
-    right: 100%;
-  }
-  60% {
-    left: 107%;
-    right: -8%;
-  }
-  100% {
-    left: 107%;
-    right: -8%;
-  }
-}
-
-@keyframes indeterminate-short {
-  0% {
-    left: -200%;
-    right: 100%;
-  }
-  60% {
-    left: 107%;
-    right: -8%;
-  }
-  100% {
-    left: 107%;
-    right: -8%;
-  }
-}
-
-/*******************
-  Utility Classes
-*******************/
-.hide {
-  display: none !important;
-}
-
-.left-align {
-  text-align: left;
-}
-
-.right-align {
-  text-align: right;
-}
-
-.center, .center-align {
-  text-align: center;
-}
-
-.left {
-  float: left !important;
-}
-
-.right {
-  float: right !important;
-}
-
-.no-select, input[type=range],
-input[type=range] + .thumb {
-  -webkit-touch-callout: none;
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-  user-select: none;
-}
-
-.circle {
-  border-radius: 50%;
-}
-
-.center-block {
-  display: block;
-  margin-left: auto;
-  margin-right: auto;
-}
-
-.truncate {
-  display: block;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
-.no-padding {
-  padding: 0 !important;
-}
-
-span.badge {
-  min-width: 3rem;
-  padding: 0 6px;
-  margin-left: 14px;
-  text-align: center;
-  font-size: 1rem;
-  line-height: 22px;
-  height: 22px;
-  color: #757575;
-  float: right;
-  box-sizing: border-box;
-}
-
-span.badge.new {
-  font-weight: 300;
-  font-size: 0.8rem;
-  color: #fff;
-  background-color: #26a69a;
-  border-radius: 2px;
-}
-
-span.badge.new:after {
-  content: " new";
-}
-
-span.badge[data-badge-caption]::after {
-  content: " " attr(data-badge-caption);
-}
-
-nav ul a span.badge {
-  display: inline-block;
-  float: none;
-  margin-left: 4px;
-  line-height: 22px;
-  height: 22px;
-}
-
-.collection-item span.badge {
-  margin-top: calc(0.75rem - 11px);
-}
-
-.collapsible span.badge {
-  margin-top: calc(1.5rem - 11px);
-}
-
-.side-nav span.badge {
-  margin-top: calc(24px - 11px);
-}
-
-/* This is needed for some mobile phones to display the Google Icon font properly */
-.material-icons {
-  text-rendering: optimizeLegibility;
-  -webkit-font-feature-settings: 'liga';
-     -moz-font-feature-settings: 'liga';
-          font-feature-settings: 'liga';
-}
-
-.container {
-  margin: 0 auto;
-  max-width: 1280px;
-  width: 90%;
-}
-
-@media only screen and (min-width: 601px) {
-  .container {
-    width: 85%;
-  }
-}
-
-@media only screen and (min-width: 993px) {
-  .container {
-    width: 70%;
-  }
-}
-
-.container .row {
-  margin-left: -0.75rem;
-  margin-right: -0.75rem;
-}
-
-.section {
-  padding-top: 1rem;
-  padding-bottom: 1rem;
-}
-
-.section.no-pad {
-  padding: 0;
-}
-
-.section.no-pad-bot {
-  padding-bottom: 0;
-}
-
-.section.no-pad-top {
-  padding-top: 0;
-}
-
-.row {
-  margin-left: auto;
-  margin-right: auto;
-  margin-bottom: 20px;
-}
-
-.row:after {
-  content: "";
-  display: table;
-  clear: both;
-}
-
-.row .col {
-  float: left;
-  box-sizing: border-box;
-  padding: 0 0.75rem;
-  min-height: 1px;
-}
-
-.row .col[class*="push-"], .row .col[class*="pull-"] {
-  position: relative;
-}
-
-.row .col.s1 {
-  width: 8.3333333333%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s2 {
-  width: 16.6666666667%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s3 {
-  width: 25%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s4 {
-  width: 33.3333333333%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s5 {
-  width: 41.6666666667%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s6 {
-  width: 50%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s7 {
-  width: 58.3333333333%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s8 {
-  width: 66.6666666667%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s9 {
-  width: 75%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s10 {
-  width: 83.3333333333%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s11 {
-  width: 91.6666666667%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.s12 {
-  width: 100%;
-  margin-left: auto;
-  left: auto;
-  right: auto;
-}
-
-.row .col.offset-s1 {
-  margin-left: 8.3333333333%;
-}
-
-.row .col.pull-s1 {
-  right: 8.3333333333%;
-}
-
-.row .col.push-s1 {
-  left: 8.3333333333%;
-}
-
-.row .col.offset-s2 {
-  margin-left: 16.6666666667%;
-}
-
-.row .col.pull-s2 {
-  right: 16.6666666667%;
-}
-
-.row .col.push-s2 {
-  left: 16.6666666667%;
-}
-
-.row .col.offset-s3 {
-  margin-left: 25%;
-}
-
-.row .col.pull-s3 {
-  right: 25%;
-}
-
-.row .col.push-s3 {
-  left: 25%;
-}
-
-.row .col.offset-s4 {
-  margin-left: 33.3333333333%;
-}
-
-.row .col.pull-s4 {
-  right: 33.3333333333%;
-}
-
-.row .col.push-s4 {
-  left: 33.3333333333%;
-}
-
-.row .col.offset-s5 {
-  margin-left: 41.6666666667%;
-}
-
-.row .col.pull-s5 {
-  right: 41.6666666667%;
-}
-
-.row .col.push-s5 {
-  left: 41.6666666667%;
-}
-
-.row .col.offset-s6 {
-  margin-left: 50%;
-}
-
-.row .col.pull-s6 {
-  right: 50%;
-}
-
-.row .col.push-s6 {
-  left: 50%;
-}
-
-.row .col.offset-s7 {
-  margin-left: 58.3333333333%;
-}
-
-.row .col.pull-s7 {
-  right: 58.3333333333%;
-}
-
-.row .col.push-s7 {
-  left: 58.3333333333%;
-}
-
-.row .col.offset-s8 {
-  margin-left: 66.6666666667%;
-}
-
-.row .col.pull-s8 {
-  right: 66.6666666667%;
-}
-
-.row .col.push-s8 {
-  left: 66.6666666667%;
-}
-
-.row .col.offset-s9 {
-  margin-left: 75%;
-}
-
-.row .col.pull-s9 {
-  right: 75%;
-}
-
-.row .col.push-s9 {
-  left: 75%;
-}
-
-.row .col.offset-s10 {
-  margin-left: 83.3333333333%;
-}
-
-.row .col.pull-s10 {
-  right: 83.3333333333%;
-}
-
-.row .col.push-s10 {
-  left: 83.3333333333%;
-}
-
-.row .col.offset-s11 {
-  margin-left: 91.6666666667%;
-}
-
-.row .col.pull-s11 {
-  right: 91.6666666667%;
-}
-
-.row .col.push-s11 {
-  left: 91.6666666667%;
-}
-
-.row .col.offset-s12 {
-  margin-left: 100%;
-}
-
-.row .col.pull-s12 {
-  right: 100%;
-}
-
-.row .col.push-s12 {
-  left: 100%;
-}
-
-@media only screen and (min-width: 601px) {
-  .row .col.m1 {
-    width: 8.3333333333%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m2 {
-    width: 16.6666666667%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m3 {
-    width: 25%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m4 {
-    width: 33.3333333333%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m5 {
-    width: 41.6666666667%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m6 {
-    width: 50%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m7 {
-    width: 58.3333333333%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m8 {
-    width: 66.6666666667%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m9 {
-    width: 75%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m10 {
-    width: 83.3333333333%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m11 {
-    width: 91.6666666667%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.m12 {
-    width: 100%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.offset-m1 {
-    margin-left: 8.3333333333%;
-  }
-  .row .col.pull-m1 {
-    right: 8.3333333333%;
-  }
-  .row .col.push-m1 {
-    left: 8.3333333333%;
-  }
-  .row .col.offset-m2 {
-    margin-left: 16.6666666667%;
-  }
-  .row .col.pull-m2 {
-    right: 16.6666666667%;
-  }
-  .row .col.push-m2 {
-    left: 16.6666666667%;
-  }
-  .row .col.offset-m3 {
-    margin-left: 25%;
-  }
-  .row .col.pull-m3 {
-    right: 25%;
-  }
-  .row .col.push-m3 {
-    left: 25%;
-  }
-  .row .col.offset-m4 {
-    margin-left: 33.3333333333%;
-  }
-  .row .col.pull-m4 {
-    right: 33.3333333333%;
-  }
-  .row .col.push-m4 {
-    left: 33.3333333333%;
-  }
-  .row .col.offset-m5 {
-    margin-left: 41.6666666667%;
-  }
-  .row .col.pull-m5 {
-    right: 41.6666666667%;
-  }
-  .row .col.push-m5 {
-    left: 41.6666666667%;
-  }
-  .row .col.offset-m6 {
-    margin-left: 50%;
-  }
-  .row .col.pull-m6 {
-    right: 50%;
-  }
-  .row .col.push-m6 {
-    left: 50%;
-  }
-  .row .col.offset-m7 {
-    margin-left: 58.3333333333%;
-  }
-  .row .col.pull-m7 {
-    right: 58.3333333333%;
-  }
-  .row .col.push-m7 {
-    left: 58.3333333333%;
-  }
-  .row .col.offset-m8 {
-    margin-left: 66.6666666667%;
-  }
-  .row .col.pull-m8 {
-    right: 66.6666666667%;
-  }
-  .row .col.push-m8 {
-    left: 66.6666666667%;
-  }
-  .row .col.offset-m9 {
-    margin-left: 75%;
-  }
-  .row .col.pull-m9 {
-    right: 75%;
-  }
-  .row .col.push-m9 {
-    left: 75%;
-  }
-  .row .col.offset-m10 {
-    margin-left: 83.3333333333%;
-  }
-  .row .col.pull-m10 {
-    right: 83.3333333333%;
-  }
-  .row .col.push-m10 {
-    left: 83.3333333333%;
-  }
-  .row .col.offset-m11 {
-    margin-left: 91.6666666667%;
-  }
-  .row .col.pull-m11 {
-    right: 91.6666666667%;
-  }
-  .row .col.push-m11 {
-    left: 91.6666666667%;
-  }
-  .row .col.offset-m12 {
-    margin-left: 100%;
-  }
-  .row .col.pull-m12 {
-    right: 100%;
-  }
-  .row .col.push-m12 {
-    left: 100%;
-  }
-}
-
-@media only screen and (min-width: 993px) {
-  .row .col.l1 {
-    width: 8.3333333333%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l2 {
-    width: 16.6666666667%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l3 {
-    width: 25%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l4 {
-    width: 33.3333333333%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l5 {
-    width: 41.6666666667%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l6 {
-    width: 50%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l7 {
-    width: 58.3333333333%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l8 {
-    width: 66.6666666667%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l9 {
-    width: 75%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l10 {
-    width: 83.3333333333%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l11 {
-    width: 91.6666666667%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.l12 {
-    width: 100%;
-    margin-left: auto;
-    left: auto;
-    right: auto;
-  }
-  .row .col.offset-l1 {
-    margin-left: 8.3333333333%;
-  }
-  .row .col.pull-l1 {
-    right: 8.3333333333%;
-  }
-  .row .col.push-l1 {
-    left: 8.3333333333%;
-  }
-  .row .col.offset-l2 {
-    margin-left: 16.6666666667%;
-  }
-  .row .col.pull-l2 {
-    right: 16.6666666667%;
-  }
-  .row .col.push-l2 {
-    left: 16.6666666667%;
-  }
-  .row .col.offset-l3 {
-    margin-left: 25%;
-  }
-  .row .col.pull-l3 {
-    right: 25%;
-  }
-  .row .col.push-l3 {
-    left: 25%;
-  }
-  .row .col.offset-l4 {
-    margin-left: 33.3333333333%;
-  }
-  .row .col.pull-l4 {
-    right: 33.3333333333%;
-  }
-  .row .col.push-l4 {
-    left: 33.3333333333%;
-  }
-  .row .col.offset-l5 {
-    margin-left: 41.6666666667%;
-  }
-  .row .col.pull-l5 {
-    right: 41.6666666667%;
-  }
-  .row .col.push-l5 {
-    left: 41.6666666667%;
-  }
-  .row .col.offset-l6 {
-    margin-left: 50%;
-  }
-  .row .col.pull-l6 {
-    right: 50%;
-  }
-  .row .col.push-l6 {
-    left: 50%;
-  }
-  .row .col.offset-l7 {
-    margin-left: 58.3333333333%;
-  }
-  .row .col.pull-l7 {
-    right: 58.3333333333%;
-  }
-  .row .col.push-l7 {
-    left: 58.3333333333%;
-  }
-  .row .col.offset-l8 {
-    margin-left: 66.6666666667%;
-  }
-  .row .col.pull-l8 {
-    right: 66.6666666667%;
-  }
-  .row .col.push-l8 {
-    left: 66.6666666667%;
-  }
-  .row .col.offset-l9 {
-    margin-left: 75%;
-  }
-  .row .col.pull-l9 {
-    right: 75%;
-  }
-  .row .col.push-l9 {
-    left: 75%;
-  }
-  .row .col.offset-l10 {
-    margin-left: 83.3333333333%;
-  }
-  .row .col.pull-l10 {
-    right: 83.3333333333%;
-  }
-  .row .col.push-l10 {
-    left: 83.3333333333%;
-  }
-  .row .col.offset-l11 {
-    margin-left: 91.6666666667%;
-  }
-  .row .col.pull-l11 {
-    right: 91.6666666667%;
-  }
-  .row .col.push-l11 {
-    left: 91.6666666667%;
-  }
-  .row .col.offset-l12 {
-    margin-left: 100%;
-  }
-  .row .col.pull-l12 {
-    right: 100%;
-  }
-  .row .col.push-l12 {
-    left: 100%;
-  }
-}
-
-nav {
-  color: #fff;
-  background-color: #ee6e73;
-  width: 100%;
-  height: 56px;
-  line-height: 56px;
-}
-
-nav.nav-extended {
-  height: auto;
-}
-
-nav.nav-extended .nav-wrapper {
-  min-height: 56px;
-  height: auto;
-}
-
-nav.nav-extended .nav-content {
-  position: relative;
-  line-height: normal;
-}
-
-nav a {
-  color: #fff;
-}
-
-nav i,
-nav [class^="mdi-"], nav [class*="mdi-"],
-nav i.material-icons {
-  display: block;
-  font-size: 24px;
-  height: 56px;
-  line-height: 56px;
-}
-
-nav .nav-wrapper {
-  position: relative;
-  height: 100%;
-}
-
-@media only screen and (min-width: 993px) {
-  nav a.button-collapse {
-    display: none;
-  }
-}
-
-nav .button-collapse {
-  float: left;
-  position: relative;
-  z-index: 1;
-  height: 56px;
-  margin: 0 18px;
-}
-
-nav .button-collapse i {
-  height: 56px;
-  line-height: 56px;
-}
-
-nav .brand-logo {
-  position: absolute;
-  color: #fff;
-  display: inline-block;
-  font-size: 2.1rem;
-  padding: 0;
-  white-space: nowrap;
-}
-
-nav .brand-logo.center {
-  left: 50%;
-  -webkit-transform: translateX(-50%);
-          transform: translateX(-50%);
-}
-
-@media only screen and (max-width: 992px) {
-  nav .brand-logo {
-    left: 50%;
-    -webkit-transform: translateX(-50%);
-            transform: translateX(-50%);
-  }
-  nav .brand-logo.left, nav .brand-logo.right {
-    padding: 0;
-    -webkit-transform: none;
-            transform: none;
-  }
-  nav .brand-logo.left {
-    left: 0.5rem;
-  }
-  nav .brand-logo.right {
-    right: 0.5rem;
-    left: auto;
-  }
-}
-
-nav .brand-logo.right {
-  right: 0.5rem;
-  padding: 0;
-}
-
-nav .brand-logo i,
-nav .brand-logo [class^="mdi-"], nav .brand-logo [class*="mdi-"],
-nav .brand-logo i.material-icons {
-  float: left;
-  margin-right: 15px;
-}
-
-nav .nav-title {
-  display: inline-block;
-  font-size: 32px;
-  padding: 28px 0;
-}
-
-nav ul {
-  margin: 0;
-}
-
-nav ul li {
-  transition: background-color .3s;
-  float: left;
-  padding: 0;
-}
-
-nav ul li.active {
-  background-color: rgba(0, 0, 0, 0.1);
-}
-
-nav ul a {
-  transition: background-color .3s;
-  font-size: 1rem;
-  color: #fff;
-  display: block;
-  padding: 0 15px;
-  cursor: pointer;
-}
-
-nav ul a.btn, nav ul a.btn-large, nav ul a.btn-large, nav ul a.btn-flat, nav ul a.btn-floating {
-  margin-top: -2px;
-  margin-left: 15px;
-  margin-right: 15px;
-}
-
-nav ul a.btn > .material-icons, nav ul a.btn-large > .material-icons, nav ul a.btn-large > .material-icons, nav ul a.btn-flat > .material-icons, nav ul a.btn-floating > .material-icons {
-  height: inherit;
-  line-height: inherit;
-}
-
-nav ul a:hover {
-  background-color: rgba(0, 0, 0, 0.1);
-}
-
-nav ul.left {
-  float: left;
-}
-
-nav form {
-  height: 100%;
-}
-
-nav .input-field {
-  margin: 0;
-  height: 100%;
-}
-
-nav .input-field input {
-  height: 100%;
-  font-size: 1.2rem;
-  border: none;
-  padding-left: 2rem;
-}
-
-nav .input-field input:focus, nav .input-field input[type=text]:valid, nav .input-field input[type=password]:valid, nav .input-field input[type=email]:valid, nav .input-field input[type=url]:valid, nav .input-field input[type=date]:valid {
-  border: none;
-  box-shadow: none;
-}
-
-nav .input-field label {
-  top: 0;
-  left: 0;
-}
-
-nav .input-field label i {
-  color: rgba(255, 255, 255, 0.7);
-  transition: color .3s;
-}
-
-nav .input-field label.active i {
-  color: #fff;
-}
-
-.navbar-fixed {
-  position: relative;
-  height: 56px;
-  z-index: 997;
-}
-
-.navbar-fixed nav {
-  position: fixed;
-}
-
-@media only screen and (min-width: 601px) {
-  nav.nav-extended .nav-wrapper {
-    min-height: 64px;
-  }
-  nav, nav .nav-wrapper i, nav a.button-collapse, nav a.button-collapse i {
-    height: 64px;
-    line-height: 64px;
-  }
-  .navbar-fixed {
-    height: 64px;
-  }
-}
-
-@font-face {
-  font-family: "Roboto";
-  src: local(Roboto Thin), url("../fonts/roboto/Roboto-Thin.eot");
-  src: url("../fonts/roboto/Roboto-Thin.eot?#iefix") format("embedded-opentype"), url("../fonts/roboto/Roboto-Thin.woff2") format("woff2"), url("../fonts/roboto/Roboto-Thin.woff") format("woff"), url("../fonts/roboto/Roboto-Thin.ttf") format("truetype");
-  font-weight: 200;
-}
-
-@font-face {
-  font-family: "Roboto";
-  src: local(Roboto Light), url("../fonts/roboto/Roboto-Light.eot");
-  src: url("../fonts/roboto/Roboto-Light.eot?#iefix") format("embedded-opentype"), url("../fonts/roboto/Roboto-Light.woff2") format("woff2"), url("../fonts/roboto/Roboto-Light.woff") format("woff"), url("../fonts/roboto/Roboto-Light.ttf") format("truetype");
-  font-weight: 300;
-}
-
-@font-face {
-  font-family: "Roboto";
-  src: local(Roboto Regular), url("../fonts/roboto/Roboto-Regular.eot");
-  src: url("../fonts/roboto/Roboto-Regular.eot?#iefix") format("embedded-opentype"), url("../fonts/roboto/Roboto-Regular.woff2") format("woff2"), url("../fonts/roboto/Roboto-Regular.woff") format("woff"), url("../fonts/roboto/Roboto-Regular.ttf") format("truetype");
-  font-weight: 400;
-}
-
-@font-face {
-  font-family: "Roboto";
-  src: url("../fonts/roboto/Roboto-Medium.eot");
-  src: url("../fonts/roboto/Roboto-Medium.eot?#iefix") format("embedded-opentype"), url("../fonts/roboto/Roboto-Medium.woff2") format("woff2"), url("../fonts/roboto/Roboto-Medium.woff") format("woff"), url("../fonts/roboto/Roboto-Medium.ttf") format("truetype");
-  font-weight: 500;
-}
-
-@font-face {
-  font-family: "Roboto";
-  src: url("../fonts/roboto/Roboto-Bold.eot");
-  src: url("../fonts/roboto/Roboto-Bold.eot?#iefix") format("embedded-opentype"), url("../fonts/roboto/Roboto-Bold.woff2") format("woff2"), url("../fonts/roboto/Roboto-Bold.woff") format("woff"), url("../fonts/roboto/Roboto-Bold.ttf") format("truetype");
-  font-weight: 700;
-}
-
-a {
-  text-decoration: none;
-}
-
-html {
-  line-height: 1.5;
-  font-family: "Roboto", sans-serif;
-  font-weight: normal;
-  color: rgba(0, 0, 0, 0.87);
-}
-
-@media only screen and (min-width: 0) {
-  html {
-    font-size: 14px;
-  }
-}
-
-@media only screen and (min-width: 992px) {
-  html {
-    font-size: 14.5px;
-  }
-}
-
-@media only screen and (min-width: 1200px) {
-  html {
-    font-size: 15px;
-  }
-}
-
-h1, h2, h3, h4, h5, h6 {
-  font-weight: 400;
-  line-height: 1.1;
-}
-
-h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
-  font-weight: inherit;
-}
-
-h1 {
-  font-size: 4.2rem;
-  line-height: 110%;
-  margin: 2.1rem 0 1.68rem 0;
-}
-
-h2 {
-  font-size: 3.56rem;
-  line-height: 110%;
-  margin: 1.78rem 0 1.424rem 0;
-}
-
-h3 {
-  font-size: 2.92rem;
-  line-height: 110%;
-  margin: 1.46rem 0 1.168rem 0;
-}
-
-h4 {
-  font-size: 2.28rem;
-  line-height: 110%;
-  margin: 1.14rem 0 0.912rem 0;
-}
-
-h5 {
-  font-size: 1.64rem;
-  line-height: 110%;
-  margin: 0.82rem 0 0.656rem 0;
-}
-
-h6 {
-  font-size: 1rem;
-  line-height: 110%;
-  margin: 0.5rem 0 0.4rem 0;
-}
-
-em {
-  font-style: italic;
-}
-
-strong {
-  font-weight: 500;
-}
-
-small {
-  font-size: 75%;
-}
-
-.light, footer.page-footer .footer-copyright {
-  font-weight: 300;
-}
-
-.thin {
-  font-weight: 200;
-}
-
-.flow-text {
-  font-weight: 300;
-}
-
-@media only screen and (min-width: 360px) {
-  .flow-text {
-    font-size: 1.2rem;
-  }
-}
-
-@media only screen and (min-width: 390px) {
-  .flow-text {
-    font-size: 1.224rem;
-  }
-}
-
-@media only screen and (min-width: 420px) {
-  .flow-text {
-    font-size: 1.248rem;
-  }
-}
-
-@media only screen and (min-width: 450px) {
-  .flow-text {
-    font-size: 1.272rem;
-  }
-}
-
-@media only screen and (min-width: 480px) {
-  .flow-text {
-    font-size: 1.296rem;
-  }
-}
-
-@media only screen and (min-width: 510px) {
-  .flow-text {
-    font-size: 1.32rem;
-  }
-}
-
-@media only screen and (min-width: 540px) {
-  .flow-text {
-    font-size: 1.344rem;
-  }
-}
-
-@media only screen and (min-width: 570px) {
-  .flow-text {
-    font-size: 1.368rem;
-  }
-}
-
-@media only screen and (min-width: 600px) {
-  .flow-text {
-    font-size: 1.392rem;
-  }
-}
-
-@media only screen and (min-width: 630px) {
-  .flow-text {
-    font-size: 1.416rem;
-  }
-}
-
-@media only screen and (min-width: 660px) {
-  .flow-text {
-    font-size: 1.44rem;
-  }
-}
-
-@media only screen and (min-width: 690px) {
-  .flow-text {
-    font-size: 1.464rem;
-  }
-}
-
-@media only screen and (min-width: 720px) {
-  .flow-text {
-    font-size: 1.488rem;
-  }
-}
-
-@media only screen and (min-width: 750px) {
-  .flow-text {
-    font-size: 1.512rem;
-  }
-}
-
-@media only screen and (min-width: 780px) {
-  .flow-text {
-    font-size: 1.536rem;
-  }
-}
-
-@media only screen and (min-width: 810px) {
-  .flow-text {
-    font-size: 1.56rem;
-  }
-}
-
-@media only screen and (min-width: 840px) {
-  .flow-text {
-    font-size: 1.584rem;
-  }
-}
-
-@media only screen and (min-width: 870px) {
-  .flow-text {
-    font-size: 1.608rem;
-  }
-}
-
-@media only screen and (min-width: 900px) {
-  .flow-text {
-    font-size: 1.632rem;
-  }
-}
-
-@media only screen and (min-width: 930px) {
-  .flow-text {
-    font-size: 1.656rem;
-  }
-}
-
-@media only screen and (min-width: 960px) {
-  .flow-text {
-    font-size: 1.68rem;
-  }
-}
-
-@media only screen and (max-width: 360px) {
-  .flow-text {
-    font-size: 1.2rem;
-  }
-}
-
-.scale-transition {
-  transition: -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important;
-  transition: transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important;
-  transition: transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63), -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important;
-}
-
-.scale-transition.scale-out {
-  -webkit-transform: scale(0);
-          transform: scale(0);
-  transition: -webkit-transform .2s !important;
-  transition: transform .2s !important;
-  transition: transform .2s, -webkit-transform .2s !important;
-}
-
-.scale-transition.scale-in {
-  -webkit-transform: scale(1);
-          transform: scale(1);
-}
-
-.card-panel {
-  transition: box-shadow .25s;
-  padding: 24px;
-  margin: 0.5rem 0 1rem 0;
-  border-radius: 2px;
-  background-color: #fff;
-}
-
-.card {
-  position: relative;
-  margin: 0.5rem 0 1rem 0;
-  background-color: #fff;
-  transition: box-shadow .25s;
-  border-radius: 2px;
-}
-
-.card .card-title {
-  font-size: 24px;
-  font-weight: 300;
-}
-
-.card .card-title.activator {
-  cursor: pointer;
-}
-
-.card.small, .card.medium, .card.large {
-  position: relative;
-}
-
-.card.small .card-image, .card.medium .card-image, .card.large .card-image {
-  max-height: 60%;
-  overflow: hidden;
-}
-
-.card.small .card-image + .card-content, .card.medium .card-image + .card-content, .card.large .card-image + .card-content {
-  max-height: 40%;
-}
-
-.card.small .card-content, .card.medium .card-content, .card.large .card-content {
-  max-height: 100%;
-  overflow: hidden;
-}
-
-.card.small .card-action, .card.medium .card-action, .card.large .card-action {
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  right: 0;
-}
-
-.card.small {
-  height: 300px;
-}
-
-.card.medium {
-  height: 400px;
-}
-
-.card.large {
-  height: 500px;
-}
-
-.card.horizontal {
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-}
-
-.card.horizontal.small .card-image, .card.horizontal.medium .card-image, .card.horizontal.large .card-image {
-  height: 100%;
-  max-height: none;
-  overflow: visible;
-}
-
-.card.horizontal.small .card-image img, .card.horizontal.medium .card-image img, .card.horizontal.large .card-image img {
-  height: 100%;
-}
-
-.card.horizontal .card-image {
-  max-width: 50%;
-}
-
-.card.horizontal .card-image img {
-  border-radius: 2px 0 0 2px;
-  max-width: 100%;
-  width: auto;
-}
-
-.card.horizontal .card-stacked {
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-  -webkit-flex-direction: column;
-      -ms-flex-direction: column;
-          flex-direction: column;
-  -webkit-flex: 1;
-      -ms-flex: 1;
-          flex: 1;
-  position: relative;
-}
-
-.card.horizontal .card-stacked .card-content {
-  -webkit-flex-grow: 1;
-      -ms-flex-positive: 1;
-          flex-grow: 1;
-}
-
-.card.sticky-action .card-action {
-  z-index: 2;
-}
-
-.card.sticky-action .card-reveal {
-  z-index: 1;
-  padding-bottom: 64px;
-}
-
-.card .card-image {
-  position: relative;
-}
-
-.card .card-image img {
-  display: block;
-  border-radius: 2px 2px 0 0;
-  position: relative;
-  left: 0;
-  right: 0;
-  top: 0;
-  bottom: 0;
-  width: 100%;
-}
-
-.card .card-image .card-title {
-  color: #fff;
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  max-width: 100%;
-  padding: 24px;
-}
-
-.card .card-content {
-  padding: 24px;
-  border-radius: 0 0 2px 2px;
-}
-
-.card .card-content p {
-  margin: 0;
-  color: inherit;
-}
-
-.card .card-content .card-title {
-  display: block;
-  line-height: 32px;
-  margin-bottom: 8px;
-}
-
-.card .card-content .card-title i {
-  line-height: 32px;
-}
-
-.card .card-action {
-  position: relative;
-  background-color: inherit;
-  border-top: 1px solid rgba(160, 160, 160, 0.2);
-  padding: 16px 24px;
-}
-
-.card .card-action a:not(.btn):not(.btn-large):not(.btn-large):not(.btn-floating) {
-  color: #ffab40;
-  margin-right: 24px;
-  transition: color .3s ease;
-  text-transform: uppercase;
-}
-
-.card .card-action a:not(.btn):not(.btn-large):not(.btn-large):not(.btn-floating):hover {
-  color: #ffd8a6;
-}
-
-.card .card-reveal {
-  padding: 24px;
-  position: absolute;
-  background-color: #fff;
-  width: 100%;
-  overflow-y: auto;
-  left: 0;
-  top: 100%;
-  height: 100%;
-  z-index: 3;
-  display: none;
-}
-
-.card .card-reveal .card-title {
-  cursor: pointer;
-  display: block;
-}
-
-#toast-container {
-  display: block;
-  position: fixed;
-  z-index: 10000;
-}
-
-@media only screen and (max-width: 600px) {
-  #toast-container {
-    min-width: 100%;
-    bottom: 0%;
-  }
-}
-
-@media only screen and (min-width: 601px) and (max-width: 992px) {
-  #toast-container {
-    left: 5%;
-    bottom: 7%;
-    max-width: 90%;
-  }
-}
-
-@media only screen and (min-width: 993px) {
-  #toast-container {
-    top: 10%;
-    right: 7%;
-    max-width: 86%;
-  }
-}
-
-.toast {
-  border-radius: 2px;
-  top: 35px;
-  width: auto;
-  clear: both;
-  margin-top: 10px;
-  position: relative;
-  max-width: 100%;
-  height: auto;
-  min-height: 48px;
-  line-height: 1.5em;
-  word-break: break-all;
-  background-color: #323232;
-  padding: 10px 25px;
-  font-size: 1.1rem;
-  font-weight: 300;
-  color: #fff;
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-  -webkit-align-items: center;
-      -ms-flex-align: center;
-          align-items: center;
-  -webkit-justify-content: space-between;
-      -ms-flex-pack: justify;
-          justify-content: space-between;
-}
-
-.toast .btn, .toast .btn-large, .toast .btn-flat {
-  margin: 0;
-  margin-left: 3rem;
-}
-
-.toast.rounded {
-  border-radius: 24px;
-}
-
-@media only screen and (max-width: 600px) {
-  .toast {
-    width: 100%;
-    border-radius: 0;
-  }
-}
-
-@media only screen and (min-width: 601px) and (max-width: 992px) {
-  .toast {
-    float: left;
-  }
-}
-
-@media only screen and (min-width: 993px) {
-  .toast {
-    float: right;
-  }
-}
-
-.tabs {
-  position: relative;
-  overflow-x: auto;
-  overflow-y: hidden;
-  height: 48px;
-  width: 100%;
-  background-color: #fff;
-  margin: 0 auto;
-  white-space: nowrap;
-}
-
-.tabs.tabs-transparent {
-  background-color: transparent;
-}
-
-.tabs.tabs-transparent .tab a,
-.tabs.tabs-transparent .tab.disabled a,
-.tabs.tabs-transparent .tab.disabled a:hover {
-  color: rgba(255, 255, 255, 0.7);
-}
-
-.tabs.tabs-transparent .tab a:hover,
-.tabs.tabs-transparent .tab a.active {
-  color: #fff;
-}
-
-.tabs.tabs-transparent .indicator {
-  background-color: #fff;
-}
-
-.tabs.tabs-fixed-width {
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-}
-
-.tabs.tabs-fixed-width .tab {
-  -webkit-flex-grow: 1;
-  -ms-flex-positive: 1;
-  flex-grow: 1;
-}
-
-.tabs .tab {
-  display: inline-block;
-  text-align: center;
-  line-height: 48px;
-  height: 48px;
-  padding: 0;
-  margin: 0;
-  text-transform: uppercase;
-}
-
-.tabs .tab a {
-  color: rgba(238, 110, 115, 0.7);
-  display: block;
-  width: 100%;
-  height: 100%;
-  padding: 0 24px;
-  font-size: 14px;
-  text-overflow: ellipsis;
-  overflow: hidden;
-  transition: color .28s ease;
-}
-
-.tabs .tab a:hover, .tabs .tab a.active {
-  background-color: transparent;
-  color: #ee6e73;
-}
-
-.tabs .tab.disabled a,
-.tabs .tab.disabled a:hover {
-  color: rgba(238, 110, 115, 0.7);
-  cursor: default;
-}
-
-.tabs .indicator {
-  position: absolute;
-  bottom: 0;
-  height: 2px;
-  background-color: #f6b2b5;
-  will-change: left, right;
-}
-
-@media only screen and (max-width: 992px) {
-  .tabs {
-    display: -webkit-flex;
-    display: -ms-flexbox;
-    display: flex;
-  }
-  .tabs .tab {
-    -webkit-flex-grow: 1;
-    -ms-flex-positive: 1;
-    flex-grow: 1;
-  }
-  .tabs .tab a {
-    padding: 0 12px;
-  }
-}
-
-.material-tooltip {
-  padding: 10px 8px;
-  font-size: 1rem;
-  z-index: 2000;
-  background-color: transparent;
-  border-radius: 2px;
-  color: #fff;
-  min-height: 36px;
-  line-height: 120%;
-  opacity: 0;
-  position: absolute;
-  text-align: center;
-  max-width: calc(100% - 4px);
-  overflow: hidden;
-  left: 0;
-  top: 0;
-  pointer-events: none;
-  visibility: hidden;
-}
-
-.backdrop {
-  position: absolute;
-  opacity: 0;
-  height: 7px;
-  width: 14px;
-  border-radius: 0 0 50% 50%;
-  background-color: #323232;
-  z-index: -1;
-  -webkit-transform-origin: 50% 0%;
-          transform-origin: 50% 0%;
-  visibility: hidden;
-}
-
-.btn, .btn-large,
-.btn-flat {
-  border: none;
-  border-radius: 2px;
-  display: inline-block;
-  height: 36px;
-  line-height: 36px;
-  padding: 0 2rem;
-  text-transform: uppercase;
-  vertical-align: middle;
-  -webkit-tap-highlight-color: transparent;
-}
-
-.btn.disabled, .disabled.btn-large,
-.btn-floating.disabled,
-.btn-large.disabled,
-.btn-flat.disabled,
-.btn:disabled,
-.btn-large:disabled,
-.btn-floating:disabled,
-.btn-large:disabled,
-.btn-flat:disabled,
-.btn[disabled],
-[disabled].btn-large,
-.btn-floating[disabled],
-.btn-large[disabled],
-.btn-flat[disabled] {
-  pointer-events: none;
-  background-color: #DFDFDF !important;
-  box-shadow: none;
-  color: #9F9F9F !important;
-  cursor: default;
-}
-
-.btn.disabled:hover, .disabled.btn-large:hover,
-.btn-floating.disabled:hover,
-.btn-large.disabled:hover,
-.btn-flat.disabled:hover,
-.btn:disabled:hover,
-.btn-large:disabled:hover,
-.btn-floating:disabled:hover,
-.btn-large:disabled:hover,
-.btn-flat:disabled:hover,
-.btn[disabled]:hover,
-[disabled].btn-large:hover,
-.btn-floating[disabled]:hover,
-.btn-large[disabled]:hover,
-.btn-flat[disabled]:hover {
-  background-color: #DFDFDF !important;
-  color: #9F9F9F !important;
-}
-
-.btn, .btn-large,
-.btn-floating,
-.btn-large,
-.btn-flat {
-  outline: 0;
-}
-
-.btn i, .btn-large i,
-.btn-floating i,
-.btn-large i,
-.btn-flat i {
-  font-size: 1.3rem;
-  line-height: inherit;
-}
-
-.btn:focus, .btn-large:focus,
-.btn-floating:focus {
-  background-color: #1d7d74;
-}
-
-.btn, .btn-large {
-  text-decoration: none;
-  color: #fff;
-  background-color: #26a69a;
-  text-align: center;
-  letter-spacing: .5px;
-  transition: .2s ease-out;
-  cursor: pointer;
-}
-
-.btn:hover, .btn-large:hover {
-  background-color: #2bbbad;
-}
-
-.btn-floating {
-  display: inline-block;
-  color: #fff;
-  position: relative;
-  overflow: hidden;
-  z-index: 1;
-  width: 40px;
-  height: 40px;
-  line-height: 40px;
-  padding: 0;
-  background-color: #26a69a;
-  border-radius: 50%;
-  transition: .3s;
-  cursor: pointer;
-  vertical-align: middle;
-}
-
-.btn-floating:hover {
-  background-color: #26a69a;
-}
-
-.btn-floating:before {
-  border-radius: 0;
-}
-
-.btn-floating.btn-large {
-  width: 56px;
-  height: 56px;
-}
-
-.btn-floating.btn-large i {
-  line-height: 56px;
-}
-
-.btn-floating.halfway-fab {
-  position: absolute;
-  right: 24px;
-  bottom: 0;
-  -webkit-transform: translateY(50%);
-          transform: translateY(50%);
-}
-
-.btn-floating.halfway-fab.left {
-  right: auto;
-  left: 24px;
-}
-
-.btn-floating i {
-  width: inherit;
-  display: inline-block;
-  text-align: center;
-  color: #fff;
-  font-size: 1.6rem;
-  line-height: 40px;
-}
-
-button.btn-floating {
-  border: none;
-}
-
-.fixed-action-btn {
-  position: fixed;
-  right: 23px;
-  bottom: 23px;
-  padding-top: 15px;
-  margin-bottom: 0;
-  z-index: 998;
-}
-
-.fixed-action-btn.active ul {
-  visibility: visible;
-}
-
-.fixed-action-btn.horizontal {
-  padding: 0 0 0 15px;
-}
-
-.fixed-action-btn.horizontal ul {
-  text-align: right;
-  right: 64px;
-  top: 50%;
-  -webkit-transform: translateY(-50%);
-          transform: translateY(-50%);
-  height: 100%;
-  left: auto;
-  width: 500px;
-  /*width 100% only goes to width of button container */
-}
-
-.fixed-action-btn.horizontal ul li {
-  display: inline-block;
-  margin: 15px 15px 0 0;
-}
-
-.fixed-action-btn.toolbar {
-  padding: 0;
-  height: 56px;
-}
-
-.fixed-action-btn.toolbar.active > a i {
-  opacity: 0;
-}
-
-.fixed-action-btn.toolbar ul {
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-  top: 0;
-  bottom: 0;
-}
-
-.fixed-action-btn.toolbar ul li {
-  -webkit-flex: 1;
-      -ms-flex: 1;
-          flex: 1;
-  display: inline-block;
-  margin: 0;
-  height: 100%;
-  transition: none;
-}
-
-.fixed-action-btn.toolbar ul li a {
-  display: block;
-  overflow: hidden;
-  position: relative;
-  width: 100%;
-  height: 100%;
-  background-color: transparent;
-  box-shadow: none;
-  color: #fff;
-  line-height: 56px;
-  z-index: 1;
-}
-
-.fixed-action-btn.toolbar ul li a i {
-  line-height: inherit;
-}
-
-.fixed-action-btn ul {
-  left: 0;
-  right: 0;
-  text-align: center;
-  position: absolute;
-  bottom: 64px;
-  margin: 0;
-  visibility: hidden;
-}
-
-.fixed-action-btn ul li {
-  margin-bottom: 15px;
-}
-
-.fixed-action-btn ul a.btn-floating {
-  opacity: 0;
-}
-
-.fixed-action-btn .fab-backdrop {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: -1;
-  width: 40px;
-  height: 40px;
-  background-color: #26a69a;
-  border-radius: 50%;
-  -webkit-transform: scale(0);
-          transform: scale(0);
-}
-
-.btn-flat {
-  box-shadow: none;
-  background-color: transparent;
-  color: #343434;
-  cursor: pointer;
-  transition: background-color .2s;
-}
-
-.btn-flat:focus, .btn-flat:active {
-  background-color: transparent;
-}
-
-.btn-flat:focus, .btn-flat:hover {
-  background-color: rgba(0, 0, 0, 0.1);
-  box-shadow: none;
-}
-
-.btn-flat:active {
-  background-color: rgba(0, 0, 0, 0.2);
-}
-
-.btn-flat.disabled {
-  background-color: transparent !important;
-  color: #b3b3b3 !important;
-  cursor: default;
-}
-
-.btn-large {
-  height: 54px;
-  line-height: 54px;
-}
-
-.btn-large i {
-  font-size: 1.6rem;
-}
-
-.btn-block {
-  display: block;
-}
-
-.dropdown-content {
-  background-color: #fff;
-  margin: 0;
-  display: none;
-  min-width: 100px;
-  max-height: 650px;
-  overflow-y: auto;
-  opacity: 0;
-  position: absolute;
-  z-index: 999;
-  will-change: width, height;
-}
-
-.dropdown-content li {
-  clear: both;
-  color: rgba(0, 0, 0, 0.87);
-  cursor: pointer;
-  min-height: 50px;
-  line-height: 1.5rem;
-  width: 100%;
-  text-align: left;
-  text-transform: none;
-}
-
-.dropdown-content li:hover, .dropdown-content li.active, .dropdown-content li.selected {
-  background-color: #eee;
-}
-
-.dropdown-content li.active.selected {
-  background-color: #e1e1e1;
-}
-
-.dropdown-content li.divider {
-  min-height: 0;
-  height: 1px;
-}
-
-.dropdown-content li > a, .dropdown-content li > span {
-  font-size: 16px;
-  color: #26a69a;
-  display: block;
-  line-height: 22px;
-  padding: 14px 16px;
-}
-
-.dropdown-content li > span > label {
-  top: 1px;
-  left: 0;
-  height: 18px;
-}
-
-.dropdown-content li > a > i {
-  height: inherit;
-  line-height: inherit;
-}
-
-.input-field.col .dropdown-content [type="checkbox"] + label {
-  top: 1px;
-  left: 0;
-  height: 18px;
-}
-
-/*!
- * Waves v0.6.0
- * http://fian.my.id/Waves
- *
- * Copyright 2014 Alfiana E. Sibuea and other contributors
- * Released under the MIT license
- * https://github.com/fians/Waves/blob/master/LICENSE
- */
-.waves-effect {
-  position: relative;
-  cursor: pointer;
-  display: inline-block;
-  overflow: hidden;
-  -webkit-user-select: none;
-     -moz-user-select: none;
-      -ms-user-select: none;
-          user-select: none;
-  -webkit-tap-highlight-color: transparent;
-  vertical-align: middle;
-  z-index: 1;
-  transition: .3s ease-out;
-}
-
-.waves-effect .waves-ripple {
-  position: absolute;
-  border-radius: 50%;
-  width: 20px;
-  height: 20px;
-  margin-top: -10px;
-  margin-left: -10px;
-  opacity: 0;
-  background: rgba(0, 0, 0, 0.2);
-  transition: all 0.7s ease-out;
-  transition-property: opacity, -webkit-transform;
-  transition-property: transform, opacity;
-  transition-property: transform, opacity, -webkit-transform;
-  -webkit-transform: scale(0);
-          transform: scale(0);
-  pointer-events: none;
-}
-
-.waves-effect.waves-light .waves-ripple {
-  background-color: rgba(255, 255, 255, 0.45);
-}
-
-.waves-effect.waves-red .waves-ripple {
-  background-color: rgba(244, 67, 54, 0.7);
-}
-
-.waves-effect.waves-yellow .waves-ripple {
-  background-color: rgba(255, 235, 59, 0.7);
-}
-
-.waves-effect.waves-orange .waves-ripple {
-  background-color: rgba(255, 152, 0, 0.7);
-}
-
-.waves-effect.waves-purple .waves-ripple {
-  background-color: rgba(156, 39, 176, 0.7);
-}
-
-.waves-effect.waves-green .waves-ripple {
-  background-color: rgba(76, 175, 80, 0.7);
-}
-
-.waves-effect.waves-teal .waves-ripple {
-  background-color: rgba(0, 150, 136, 0.7);
-}
-
-.waves-effect input[type="button"], .waves-effect input[type="reset"], .waves-effect input[type="submit"] {
-  border: 0;
-  font-style: normal;
-  font-size: inherit;
-  text-transform: inherit;
-  background: none;
-}
-
-.waves-effect img {
-  position: relative;
-  z-index: -1;
-}
-
-.waves-notransition {
-  transition: none !important;
-}
-
-.waves-circle {
-  -webkit-transform: translateZ(0);
-          transform: translateZ(0);
-  -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%);
-}
-
-.waves-input-wrapper {
-  border-radius: 0.2em;
-  vertical-align: bottom;
-}
-
-.waves-input-wrapper .waves-button-input {
-  position: relative;
-  top: 0;
-  left: 0;
-  z-index: 1;
-}
-
-.waves-circle {
-  text-align: center;
-  width: 2.5em;
-  height: 2.5em;
-  line-height: 2.5em;
-  border-radius: 50%;
-  -webkit-mask-image: none;
-}
-
-.waves-block {
-  display: block;
-}
-
-/* Firefox Bug: link not triggered */
-.waves-effect .waves-ripple {
-  z-index: -1;
-}
-
-.modal {
-  display: none;
-  position: fixed;
-  left: 0;
-  right: 0;
-  background-color: #fafafa;
-  padding: 0;
-  max-height: 70%;
-  width: 55%;
-  margin: auto;
-  overflow-y: auto;
-  border-radius: 2px;
-  will-change: top, opacity;
-}
-
-@media only screen and (max-width: 992px) {
-  .modal {
-    width: 80%;
-  }
-}
-
-.modal h1, .modal h2, .modal h3, .modal h4 {
-  margin-top: 0;
-}
-
-.modal .modal-content {
-  padding: 24px;
-}
-
-.modal .modal-close {
-  cursor: pointer;
-}
-
-.modal .modal-footer {
-  border-radius: 0 0 2px 2px;
-  background-color: #fafafa;
-  padding: 4px 6px;
-  height: 56px;
-  width: 100%;
-}
-
-.modal .modal-footer .btn, .modal .modal-footer .btn-large, .modal .modal-footer .btn-flat {
-  float: right;
-  margin: 6px 0;
-}
-
-.modal-overlay {
-  position: fixed;
-  z-index: 999;
-  top: -100px;
-  left: 0;
-  bottom: 0;
-  right: 0;
-  height: 125%;
-  width: 100%;
-  background: #000;
-  display: none;
-  will-change: opacity;
-}
-
-.modal.modal-fixed-footer {
-  padding: 0;
-  height: 70%;
-}
-
-.modal.modal-fixed-footer .modal-content {
-  position: absolute;
-  height: calc(100% - 56px);
-  max-height: 100%;
-  width: 100%;
-  overflow-y: auto;
-}
-
-.modal.modal-fixed-footer .modal-footer {
-  border-top: 1px solid rgba(0, 0, 0, 0.1);
-  position: absolute;
-  bottom: 0;
-}
-
-.modal.bottom-sheet {
-  top: auto;
-  bottom: -100%;
-  margin: 0;
-  width: 100%;
-  max-height: 45%;
-  border-radius: 0;
-  will-change: bottom, opacity;
-}
-
-.collapsible {
-  border-top: 1px solid #ddd;
-  border-right: 1px solid #ddd;
-  border-left: 1px solid #ddd;
-  margin: 0.5rem 0 1rem 0;
-}
-
-.collapsible-header {
-  display: block;
-  cursor: pointer;
-  min-height: 3rem;
-  line-height: 3rem;
-  padding: 0 1rem;
-  background-color: #fff;
-  border-bottom: 1px solid #ddd;
-}
-
-.collapsible-header i {
-  width: 2rem;
-  font-size: 1.6rem;
-  line-height: 3rem;
-  display: block;
-  float: left;
-  text-align: center;
-  margin-right: 1rem;
-}
-
-.collapsible-body {
-  display: none;
-  border-bottom: 1px solid #ddd;
-  box-sizing: border-box;
-  padding: 2rem;
-}
-
-.side-nav .collapsible,
-.side-nav.fixed .collapsible {
-  border: none;
-  box-shadow: none;
-}
-
-.side-nav .collapsible li,
-.side-nav.fixed .collapsible li {
-  padding: 0;
-}
-
-.side-nav .collapsible-header,
-.side-nav.fixed .collapsible-header {
-  background-color: transparent;
-  border: none;
-  line-height: inherit;
-  height: inherit;
-  padding: 0 16px;
-}
-
-.side-nav .collapsible-header:hover,
-.side-nav.fixed .collapsible-header:hover {
-  background-color: rgba(0, 0, 0, 0.05);
-}
-
-.side-nav .collapsible-header i,
-.side-nav.fixed .collapsible-header i {
-  line-height: inherit;
-}
-
-.side-nav .collapsible-body,
-.side-nav.fixed .collapsible-body {
-  border: 0;
-  background-color: #fff;
-}
-
-.side-nav .collapsible-body li a,
-.side-nav.fixed .collapsible-body li a {
-  padding: 0 23.5px 0 31px;
-}
-
-.collapsible.popout {
-  border: none;
-  box-shadow: none;
-}
-
-.collapsible.popout > li {
-  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
-  margin: 0 24px;
-  transition: margin 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94);
-}
-
-.collapsible.popout > li.active {
-  box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
-  margin: 16px 0;
-}
-
-.chip {
-  display: inline-block;
-  height: 32px;
-  font-size: 13px;
-  font-weight: 500;
-  color: rgba(0, 0, 0, 0.6);
-  line-height: 32px;
-  padding: 0 12px;
-  border-radius: 16px;
-  background-color: #e4e4e4;
-  margin-bottom: 5px;
-  margin-right: 5px;
-}
-
-.chip img {
-  float: left;
-  margin: 0 8px 0 -12px;
-  height: 32px;
-  width: 32px;
-  border-radius: 50%;
-}
-
-.chip .close {
-  cursor: pointer;
-  float: right;
-  font-size: 16px;
-  line-height: 32px;
-  padding-left: 8px;
-}
-
-.chips {
-  border: none;
-  border-bottom: 1px solid #9e9e9e;
-  box-shadow: none;
-  margin: 0 0 20px 0;
-  min-height: 45px;
-  outline: none;
-  transition: all .3s;
-}
-
-.chips.focus {
-  border-bottom: 1px solid #26a69a;
-  box-shadow: 0 1px 0 0 #26a69a;
-}
-
-.chips:hover {
-  cursor: text;
-}
-
-.chips .chip.selected {
-  background-color: #26a69a;
-  color: #fff;
-}
-
-.chips .input {
-  background: none;
-  border: 0;
-  color: rgba(0, 0, 0, 0.6);
-  display: inline-block;
-  font-size: 1rem;
-  height: 3rem;
-  line-height: 32px;
-  outline: 0;
-  margin: 0;
-  padding: 0 !important;
-  width: 120px !important;
-}
-
-.chips .input:focus {
-  border: 0 !important;
-  box-shadow: none !important;
-}
-
-.prefix ~ .chips {
-  margin-left: 3rem;
-  width: 92%;
-  width: calc(100% - 3rem);
-}
-
-.chips:empty ~ label {
-  font-size: 0.8rem;
-  -webkit-transform: translateY(-140%);
-          transform: translateY(-140%);
-}
-
-.materialboxed {
-  display: block;
-  cursor: -webkit-zoom-in;
-  cursor: zoom-in;
-  position: relative;
-  transition: opacity .4s;
-  -webkit-backface-visibility: hidden;
-}
-
-.materialboxed:hover:not(.active) {
-  opacity: .8;
-}
-
-.materialboxed.active {
-  cursor: -webkit-zoom-out;
-  cursor: zoom-out;
-}
-
-#materialbox-overlay {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  background-color: #292929;
-  z-index: 1000;
-  will-change: opacity;
-}
-
-.materialbox-caption {
-  position: fixed;
-  display: none;
-  color: #fff;
-  line-height: 50px;
-  bottom: 0;
-  left: 0;
-  width: 100%;
-  text-align: center;
-  padding: 0% 15%;
-  height: 50px;
-  z-index: 1000;
-  -webkit-font-smoothing: antialiased;
-}
-
-select:focus {
-  outline: 1px solid #c9f3ef;
-}
-
-button:focus {
-  outline: none;
-  background-color: #2ab7a9;
-}
-
-label {
-  font-size: 0.8rem;
-  color: #9e9e9e;
-}
-
-/* Text Inputs + Textarea
-   ========================================================================== */
-/* Style Placeholders */
-::-webkit-input-placeholder {
-  color: #d1d1d1;
-}
-
-:-moz-placeholder {
-  /* Firefox 18- */
-  color: #d1d1d1;
-}
-
-::-moz-placeholder {
-  /* Firefox 19+ */
-  color: #d1d1d1;
-}
-
-:-ms-input-placeholder {
-  color: #d1d1d1;
-}
-
-/* Text inputs */
-input:not([type]),
-input[type=text],
-input[type=password],
-input[type=email],
-input[type=url],
-input[type=time],
-input[type=date],
-input[type=datetime],
-input[type=datetime-local],
-input[type=tel],
-input[type=number],
-input[type=search],
-textarea.materialize-textarea {
-  background-color: transparent;
-  border: none;
-  border-bottom: 1px solid #9e9e9e;
-  border-radius: 0;
-  outline: none;
-  height: 3rem;
-  width: 100%;
-  font-size: 1rem;
-  margin: 0 0 20px 0;
-  padding: 0;
-  box-shadow: none;
-  box-sizing: content-box;
-  transition: all 0.3s;
-}
-
-input:not([type]):disabled, input:not([type])[readonly="readonly"],
-input[type=text]:disabled,
-input[type=text][readonly="readonly"],
-input[type=password]:disabled,
-input[type=password][readonly="readonly"],
-input[type=email]:disabled,
-input[type=email][readonly="readonly"],
-input[type=url]:disabled,
-input[type=url][readonly="readonly"],
-input[type=time]:disabled,
-input[type=time][readonly="readonly"],
-input[type=date]:disabled,
-input[type=date][readonly="readonly"],
-input[type=datetime]:disabled,
-input[type=datetime][readonly="readonly"],
-input[type=datetime-local]:disabled,
-input[type=datetime-local][readonly="readonly"],
-input[type=tel]:disabled,
-input[type=tel][readonly="readonly"],
-input[type=number]:disabled,
-input[type=number][readonly="readonly"],
-input[type=search]:disabled,
-input[type=search][readonly="readonly"],
-textarea.materialize-textarea:disabled,
-textarea.materialize-textarea[readonly="readonly"] {
-  color: rgba(0, 0, 0, 0.26);
-  border-bottom: 1px dotted rgba(0, 0, 0, 0.26);
-}
-
-input:not([type]):disabled + label,
-input:not([type])[readonly="readonly"] + label,
-input[type=text]:disabled + label,
-input[type=text][readonly="readonly"] + label,
-input[type=password]:disabled + label,
-input[type=password][readonly="readonly"] + label,
-input[type=email]:disabled + label,
-input[type=email][readonly="readonly"] + label,
-input[type=url]:disabled + label,
-input[type=url][readonly="readonly"] + label,
-input[type=time]:disabled + label,
-input[type=time][readonly="readonly"] + label,
-input[type=date]:disabled + label,
-input[type=date][readonly="readonly"] + label,
-input[type=datetime]:disabled + label,
-input[type=datetime][readonly="readonly"] + label,
-input[type=datetime-local]:disabled + label,
-input[type=datetime-local][readonly="readonly"] + label,
-input[type=tel]:disabled + label,
-input[type=tel][readonly="readonly"] + label,
-input[type=number]:disabled + label,
-input[type=number][readonly="readonly"] + label,
-input[type=search]:disabled + label,
-input[type=search][readonly="readonly"] + label,
-textarea.materialize-textarea:disabled + label,
-textarea.materialize-textarea[readonly="readonly"] + label {
-  color: rgba(0, 0, 0, 0.26);
-}
-
-input:not([type]):focus:not([readonly]),
-input[type=text]:focus:not([readonly]),
-input[type=password]:focus:not([readonly]),
-input[type=email]:focus:not([readonly]),
-input[type=url]:focus:not([readonly]),
-input[type=time]:focus:not([readonly]),
-input[type=date]:focus:not([readonly]),
-input[type=datetime]:focus:not([readonly]),
-input[type=datetime-local]:focus:not([readonly]),
-input[type=tel]:focus:not([readonly]),
-input[type=number]:focus:not([readonly]),
-input[type=search]:focus:not([readonly]),
-textarea.materialize-textarea:focus:not([readonly]) {
-  border-bottom: 1px solid #26a69a;
-  box-shadow: 0 1px 0 0 #26a69a;
-}
-
-input:not([type]):focus:not([readonly]) + label,
-input[type=text]:focus:not([readonly]) + label,
-input[type=password]:focus:not([readonly]) + label,
-input[type=email]:focus:not([readonly]) + label,
-input[type=url]:focus:not([readonly]) + label,
-input[type=time]:focus:not([readonly]) + label,
-input[type=date]:focus:not([readonly]) + label,
-input[type=datetime]:focus:not([readonly]) + label,
-input[type=datetime-local]:focus:not([readonly]) + label,
-input[type=tel]:focus:not([readonly]) + label,
-input[type=number]:focus:not([readonly]) + label,
-input[type=search]:focus:not([readonly]) + label,
-textarea.materialize-textarea:focus:not([readonly]) + label {
-  color: #26a69a;
-}
-
-input:not([type]).valid, input:not([type]):focus.valid,
-input[type=text].valid,
-input[type=text]:focus.valid,
-input[type=password].valid,
-input[type=password]:focus.valid,
-input[type=email].valid,
-input[type=email]:focus.valid,
-input[type=url].valid,
-input[type=url]:focus.valid,
-input[type=time].valid,
-input[type=time]:focus.valid,
-input[type=date].valid,
-input[type=date]:focus.valid,
-input[type=datetime].valid,
-input[type=datetime]:focus.valid,
-input[type=datetime-local].valid,
-input[type=datetime-local]:focus.valid,
-input[type=tel].valid,
-input[type=tel]:focus.valid,
-input[type=number].valid,
-input[type=number]:focus.valid,
-input[type=search].valid,
-input[type=search]:focus.valid,
-textarea.materialize-textarea.valid,
-textarea.materialize-textarea:focus.valid {
-  border-bottom: 1px solid #4CAF50;
-  box-shadow: 0 1px 0 0 #4CAF50;
-}
-
-input:not([type]).valid + label:after,
-input:not([type]):focus.valid + label:after,
-input[type=text].valid + label:after,
-input[type=text]:focus.valid + label:after,
-input[type=password].valid + label:after,
-input[type=password]:focus.valid + label:after,
-input[type=email].valid + label:after,
-input[type=email]:focus.valid + label:after,
-input[type=url].valid + label:after,
-input[type=url]:focus.valid + label:after,
-input[type=time].valid + label:after,
-input[type=time]:focus.valid + label:after,
-input[type=date].valid + label:after,
-input[type=date]:focus.valid + label:after,
-input[type=datetime].valid + label:after,
-input[type=datetime]:focus.valid + label:after,
-input[type=datetime-local].valid + label:after,
-input[type=datetime-local]:focus.valid + label:after,
-input[type=tel].valid + label:after,
-input[type=tel]:focus.valid + label:after,
-input[type=number].valid + label:after,
-input[type=number]:focus.valid + label:after,
-input[type=search].valid + label:after,
-input[type=search]:focus.valid + label:after,
-textarea.materialize-textarea.valid + label:after,
-textarea.materialize-textarea:focus.valid + label:after {
-  content: attr(data-success);
-  color: #4CAF50;
-  opacity: 1;
-}
-
-input:not([type]).invalid, input:not([type]):focus.invalid,
-input[type=text].invalid,
-input[type=text]:focus.invalid,
-input[type=password].invalid,
-input[type=password]:focus.invalid,
-input[type=email].invalid,
-input[type=email]:focus.invalid,
-input[type=url].invalid,
-input[type=url]:focus.invalid,
-input[type=time].invalid,
-input[type=time]:focus.invalid,
-input[type=date].invalid,
-input[type=date]:focus.invalid,
-input[type=datetime].invalid,
-input[type=datetime]:focus.invalid,
-input[type=datetime-local].invalid,
-input[type=datetime-local]:focus.invalid,
-input[type=tel].invalid,
-input[type=tel]:focus.invalid,
-input[type=number].invalid,
-input[type=number]:focus.invalid,
-input[type=search].invalid,
-input[type=search]:focus.invalid,
-textarea.materialize-textarea.invalid,
-textarea.materialize-textarea:focus.invalid {
-  border-bottom: 1px solid #F44336;
-  box-shadow: 0 1px 0 0 #F44336;
-}
-
-input:not([type]).invalid + label:after,
-input:not([type]):focus.invalid + label:after,
-input[type=text].invalid + label:after,
-input[type=text]:focus.invalid + label:after,
-input[type=password].invalid + label:after,
-input[type=password]:focus.invalid + label:after,
-input[type=email].invalid + label:after,
-input[type=email]:focus.invalid + label:after,
-input[type=url].invalid + label:after,
-input[type=url]:focus.invalid + label:after,
-input[type=time].invalid + label:after,
-input[type=time]:focus.invalid + label:after,
-input[type=date].invalid + label:after,
-input[type=date]:focus.invalid + label:after,
-input[type=datetime].invalid + label:after,
-input[type=datetime]:focus.invalid + label:after,
-input[type=datetime-local].invalid + label:after,
-input[type=datetime-local]:focus.invalid + label:after,
-input[type=tel].invalid + label:after,
-input[type=tel]:focus.invalid + label:after,
-input[type=number].invalid + label:after,
-input[type=number]:focus.invalid + label:after,
-input[type=search].invalid + label:after,
-input[type=search]:focus.invalid + label:after,
-textarea.materialize-textarea.invalid + label:after,
-textarea.materialize-textarea:focus.invalid + label:after {
-  content: attr(data-error);
-  color: #F44336;
-  opacity: 1;
-}
-
-input:not([type]).validate + label,
-input[type=text].validate + label,
-input[type=password].validate + label,
-input[type=email].validate + label,
-input[type=url].validate + label,
-input[type=time].validate + label,
-input[type=date].validate + label,
-input[type=datetime].validate + label,
-input[type=datetime-local].validate + label,
-input[type=tel].validate + label,
-input[type=number].validate + label,
-input[type=search].validate + label,
-textarea.materialize-textarea.validate + label {
-  width: 100%;
-  pointer-events: none;
-}
-
-input:not([type]) + label:after,
-input[type=text] + label:after,
-input[type=password] + label:after,
-input[type=email] + label:after,
-input[type=url] + label:after,
-input[type=time] + label:after,
-input[type=date] + label:after,
-input[type=datetime] + label:after,
-input[type=datetime-local] + label:after,
-input[type=tel] + label:after,
-input[type=number] + label:after,
-input[type=search] + label:after,
-textarea.materialize-textarea + label:after {
-  display: block;
-  content: "";
-  position: absolute;
-  top: 60px;
-  opacity: 0;
-  transition: .2s opacity ease-out, .2s color ease-out;
-}
-
-.input-field {
-  position: relative;
-  margin-top: 1rem;
-}
-
-.input-field.inline {
-  display: inline-block;
-  vertical-align: middle;
-  margin-left: 5px;
-}
-
-.input-field.inline input,
-.input-field.inline .select-dropdown {
-  margin-bottom: 1rem;
-}
-
-.input-field.col label {
-  left: 0.75rem;
-}
-
-.input-field.col .prefix ~ label,
-.input-field.col .prefix ~ .validate ~ label {
-  width: calc(100% - 3rem - 1.5rem);
-}
-
-.input-field label {
-  color: #9e9e9e;
-  position: absolute;
-  top: 0.8rem;
-  left: 0;
-  font-size: 1rem;
-  cursor: text;
-  transition: .2s ease-out;
-}
-
-.input-field label:not(.label-icon).active {
-  font-size: 0.8rem;
-  -webkit-transform: translateY(-140%);
-          transform: translateY(-140%);
-}
-
-.input-field .prefix {
-  position: absolute;
-  width: 3rem;
-  font-size: 2rem;
-  transition: color .2s;
-}
-
-.input-field .prefix.active {
-  color: #26a69a;
-}
-
-.input-field .prefix ~ input,
-.input-field .prefix ~ textarea,
-.input-field .prefix ~ label,
-.input-field .prefix ~ .validate ~ label,
-.input-field .prefix ~ .autocomplete-content {
-  margin-left: 3rem;
-  width: 92%;
-  width: calc(100% - 3rem);
-}
-
-.input-field .prefix ~ label {
-  margin-left: 3rem;
-}
-
-@media only screen and (max-width: 992px) {
-  .input-field .prefix ~ input {
-    width: 86%;
-    width: calc(100% - 3rem);
-  }
-}
-
-@media only screen and (max-width: 600px) {
-  .input-field .prefix ~ input {
-    width: 80%;
-    width: calc(100% - 3rem);
-  }
-}
-
-/* Search Field */
-.input-field input[type=search] {
-  display: block;
-  line-height: inherit;
-  padding-left: 4rem;
-  width: calc(100% - 4rem);
-}
-
-.input-field input[type=search]:focus {
-  background-color: #fff;
-  border: 0;
-  box-shadow: none;
-  color: #444;
-}
-
-.input-field input[type=search]:focus + label i,
-.input-field input[type=search]:focus ~ .mdi-navigation-close,
-.input-field input[type=search]:focus ~ .material-icons {
-  color: #444;
-}
-
-.input-field input[type=search] + label {
-  left: 1rem;
-}
-
-.input-field input[type=search] ~ .mdi-navigation-close,
-.input-field input[type=search] ~ .material-icons {
-  position: absolute;
-  top: 0;
-  right: 1rem;
-  color: transparent;
-  cursor: pointer;
-  font-size: 2rem;
-  transition: .3s color;
-}
-
-/* Textarea */
-textarea {
-  width: 100%;
-  height: 3rem;
-  background-color: transparent;
-}
-
-textarea.materialize-textarea {
-  overflow-y: hidden;
-  /* prevents scroll bar flash */
-  padding: .8rem 0 1.6rem 0;
-  /* prevents text jump on Enter keypress */
-  resize: none;
-  min-height: 3rem;
-}
-
-.hiddendiv {
-  display: none;
-  white-space: pre-wrap;
-  word-wrap: break-word;
-  overflow-wrap: break-word;
-  /* future version of deprecated 'word-wrap' */
-  padding-top: 1.2rem;
-  /* prevents text jump on Enter keypress */
-}
-
-/* Autocomplete */
-.autocomplete-content {
-  margin-top: -15px;
-  display: block;
-  opacity: 1;
-  position: static;
-}
-
-.autocomplete-content li .highlight {
-  color: #444;
-}
-
-.autocomplete-content li img {
-  height: 40px;
-  width: 40px;
-  margin: 5px 15px;
-}
-
-/* Radio Buttons
-   ========================================================================== */
-[type="radio"]:not(:checked),
-[type="radio"]:checked {
-  position: absolute;
-  left: -9999px;
-  opacity: 0;
-}
-
-[type="radio"]:not(:checked) + label,
-[type="radio"]:checked + label {
-  position: relative;
-  padding-left: 35px;
-  cursor: pointer;
-  display: inline-block;
-  height: 25px;
-  line-height: 25px;
-  font-size: 1rem;
-  transition: .28s ease;
-  /* webkit (konqueror) browsers */
-  -webkit-user-select: none;
-     -moz-user-select: none;
-      -ms-user-select: none;
-          user-select: none;
-}
-
-[type="radio"] + label:before,
-[type="radio"] + label:after {
-  content: '';
-  position: absolute;
-  left: 0;
-  top: 0;
-  margin: 4px;
-  width: 16px;
-  height: 16px;
-  z-index: 0;
-  transition: .28s ease;
-}
-
-/* Unchecked styles */
-[type="radio"]:not(:checked) + label:before,
-[type="radio"]:not(:checked) + label:after,
-[type="radio"]:checked + label:before,
-[type="radio"]:checked + label:after,
-[type="radio"].with-gap:checked + label:before,
-[type="radio"].with-gap:checked + label:after {
-  border-radius: 50%;
-}
-
-[type="radio"]:not(:checked) + label:before,
-[type="radio"]:not(:checked) + label:after {
-  border: 2px solid #5a5a5a;
-}
-
-[type="radio"]:not(:checked) + label:after {
-  -webkit-transform: scale(0);
-          transform: scale(0);
-}
-
-/* Checked styles */
-[type="radio"]:checked + label:before {
-  border: 2px solid transparent;
-}
-
-[type="radio"]:checked + label:after,
-[type="radio"].with-gap:checked + label:before,
-[type="radio"].with-gap:checked + label:after {
-  border: 2px solid #26a69a;
-}
-
-[type="radio"]:checked + label:after,
-[type="radio"].with-gap:checked + label:after {
-  background-color: #26a69a;
-}
-
-[type="radio"]:checked + label:after {
-  -webkit-transform: scale(1.02);
-          transform: scale(1.02);
-}
-
-/* Radio With gap */
-[type="radio"].with-gap:checked + label:after {
-  -webkit-transform: scale(0.5);
-          transform: scale(0.5);
-}
-
-/* Focused styles */
-[type="radio"].tabbed:focus + label:before {
-  box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1);
-}
-
-/* Disabled Radio With gap */
-[type="radio"].with-gap:disabled:checked + label:before {
-  border: 2px solid rgba(0, 0, 0, 0.26);
-}
-
-[type="radio"].with-gap:disabled:checked + label:after {
-  border: none;
-  background-color: rgba(0, 0, 0, 0.26);
-}
-
-/* Disabled style */
-[type="radio"]:disabled:not(:checked) + label:before,
-[type="radio"]:disabled:checked + label:before {
-  background-color: transparent;
-  border-color: rgba(0, 0, 0, 0.26);
-}
-
-[type="radio"]:disabled + label {
-  color: rgba(0, 0, 0, 0.26);
-}
-
-[type="radio"]:disabled:not(:checked) + label:before {
-  border-color: rgba(0, 0, 0, 0.26);
-}
-
-[type="radio"]:disabled:checked + label:after {
-  background-color: rgba(0, 0, 0, 0.26);
-  border-color: #BDBDBD;
-}
-
-/* Checkboxes
-   ========================================================================== */
-/* CUSTOM CSS CHECKBOXES */
-form p {
-  margin-bottom: 10px;
-  text-align: left;
-}
-
-form p:last-child {
-  margin-bottom: 0;
-}
-
-/* Remove default checkbox */
-[type="checkbox"]:not(:checked),
-[type="checkbox"]:checked {
-  position: absolute;
-  left: -9999px;
-  opacity: 0;
-}
-
-[type="checkbox"] {
-  /* checkbox aspect */
-}
-
-[type="checkbox"] + label {
-  position: relative;
-  padding-left: 35px;
-  cursor: pointer;
-  display: inline-block;
-  height: 25px;
-  line-height: 25px;
-  font-size: 1rem;
-  -webkit-user-select: none;
-  /* webkit (safari, chrome) browsers */
-  -moz-user-select: none;
-  /* mozilla browsers */
-  -khtml-user-select: none;
-  /* webkit (konqueror) browsers */
-  -ms-user-select: none;
-  /* IE10+ */
-}
-
-[type="checkbox"] + label:before,
-[type="checkbox"]:not(.filled-in) + label:after {
-  content: '';
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 18px;
-  height: 18px;
-  z-index: 0;
-  border: 2px solid #5a5a5a;
-  border-radius: 1px;
-  margin-top: 2px;
-  transition: .2s;
-}
-
-[type="checkbox"]:not(.filled-in) + label:after {
-  border: 0;
-  -webkit-transform: scale(0);
-          transform: scale(0);
-}
-
-[type="checkbox"]:not(:checked):disabled + label:before {
-  border: none;
-  background-color: rgba(0, 0, 0, 0.26);
-}
-
-[type="checkbox"].tabbed:focus + label:after {
-  -webkit-transform: scale(1);
-          transform: scale(1);
-  border: 0;
-  border-radius: 50%;
-  box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1);
-  background-color: rgba(0, 0, 0, 0.1);
-}
-
-[type="checkbox"]:checked + label:before {
-  top: -4px;
-  left: -5px;
-  width: 12px;
-  height: 22px;
-  border-top: 2px solid transparent;
-  border-left: 2px solid transparent;
-  border-right: 2px solid #26a69a;
-  border-bottom: 2px solid #26a69a;
-  -webkit-transform: rotate(40deg);
-          transform: rotate(40deg);
-  -webkit-backface-visibility: hidden;
-          backface-visibility: hidden;
-  -webkit-transform-origin: 100% 100%;
-          transform-origin: 100% 100%;
-}
-
-[type="checkbox"]:checked:disabled + label:before {
-  border-right: 2px solid rgba(0, 0, 0, 0.26);
-  border-bottom: 2px solid rgba(0, 0, 0, 0.26);
-}
-
-/* Indeterminate checkbox */
-[type="checkbox"]:indeterminate + label:before {
-  top: -11px;
-  left: -12px;
-  width: 10px;
-  height: 22px;
-  border-top: none;
-  border-left: none;
-  border-right: 2px solid #26a69a;
-  border-bottom: none;
-  -webkit-transform: rotate(90deg);
-          transform: rotate(90deg);
-  -webkit-backface-visibility: hidden;
-          backface-visibility: hidden;
-  -webkit-transform-origin: 100% 100%;
-          transform-origin: 100% 100%;
-}
-
-[type="checkbox"]:indeterminate:disabled + label:before {
-  border-right: 2px solid rgba(0, 0, 0, 0.26);
-  background-color: transparent;
-}
-
-[type="checkbox"].filled-in + label:after {
-  border-radius: 2px;
-}
-
-[type="checkbox"].filled-in + label:before,
-[type="checkbox"].filled-in + label:after {
-  content: '';
-  left: 0;
-  position: absolute;
-  /* .1s delay is for check animation */
-  transition: border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s;
-  z-index: 1;
-}
-
-[type="checkbox"].filled-in:not(:checked) + label:before {
-  width: 0;
-  height: 0;
-  border: 3px solid transparent;
-  left: 6px;
-  top: 10px;
-  -webkit-transform: rotateZ(37deg);
-  transform: rotateZ(37deg);
-  -webkit-transform-origin: 20% 40%;
-  transform-origin: 100% 100%;
-}
-
-[type="checkbox"].filled-in:not(:checked) + label:after {
-  height: 20px;
-  width: 20px;
-  background-color: transparent;
-  border: 2px solid #5a5a5a;
-  top: 0px;
-  z-index: 0;
-}
-
-[type="checkbox"].filled-in:checked + label:before {
-  top: 0;
-  left: 1px;
-  width: 8px;
-  height: 13px;
-  border-top: 2px solid transparent;
-  border-left: 2px solid transparent;
-  border-right: 2px solid #fff;
-  border-bottom: 2px solid #fff;
-  -webkit-transform: rotateZ(37deg);
-  transform: rotateZ(37deg);
-  -webkit-transform-origin: 100% 100%;
-  transform-origin: 100% 100%;
-}
-
-[type="checkbox"].filled-in:checked + label:after {
-  top: 0;
-  width: 20px;
-  height: 20px;
-  border: 2px solid #26a69a;
-  background-color: #26a69a;
-  z-index: 0;
-}
-
-[type="checkbox"].filled-in.tabbed:focus + label:after {
-  border-radius: 2px;
-  border-color: #5a5a5a;
-  background-color: rgba(0, 0, 0, 0.1);
-}
-
-[type="checkbox"].filled-in.tabbed:checked:focus + label:after {
-  border-radius: 2px;
-  background-color: #26a69a;
-  border-color: #26a69a;
-}
-
-[type="checkbox"].filled-in:disabled:not(:checked) + label:before {
-  background-color: transparent;
-  border: 2px solid transparent;
-}
-
-[type="checkbox"].filled-in:disabled:not(:checked) + label:after {
-  border-color: transparent;
-  background-color: #BDBDBD;
-}
-
-[type="checkbox"].filled-in:disabled:checked + label:before {
-  background-color: transparent;
-}
-
-[type="checkbox"].filled-in:disabled:checked + label:after {
-  background-color: #BDBDBD;
-  border-color: #BDBDBD;
-}
-
-/* Switch
-   ========================================================================== */
-.switch,
-.switch * {
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -khtml-user-select: none;
-  -ms-user-select: none;
-}
-
-.switch label {
-  cursor: pointer;
-}
-
-.switch label input[type=checkbox] {
-  opacity: 0;
-  width: 0;
-  height: 0;
-}
-
-.switch label input[type=checkbox]:checked + .lever {
-  background-color: #84c7c1;
-}
-
-.switch label input[type=checkbox]:checked + .lever:after {
-  background-color: #26a69a;
-  left: 24px;
-}
-
-.switch label .lever {
-  content: "";
-  display: inline-block;
-  position: relative;
-  width: 40px;
-  height: 15px;
-  background-color: #818181;
-  border-radius: 15px;
-  margin-right: 10px;
-  transition: background 0.3s ease;
-  vertical-align: middle;
-  margin: 0 16px;
-}
-
-.switch label .lever:after {
-  content: "";
-  position: absolute;
-  display: inline-block;
-  width: 21px;
-  height: 21px;
-  background-color: #F1F1F1;
-  border-radius: 21px;
-  box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4);
-  left: -5px;
-  top: -3px;
-  transition: left 0.3s ease, background .3s ease, box-shadow 0.1s ease;
-}
-
-input[type=checkbox]:checked:not(:disabled) ~ .lever:active::after,
-input[type=checkbox]:checked:not(:disabled).tabbed:focus ~ .lever::after {
-  box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4), 0 0 0 15px rgba(38, 166, 154, 0.1);
-}
-
-input[type=checkbox]:not(:disabled) ~ .lever:active:after,
-input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::after {
-  box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4), 0 0 0 15px rgba(0, 0, 0, 0.08);
-}
-
-.switch input[type=checkbox][disabled] + .lever {
-  cursor: default;
-}
-
-.switch label input[type=checkbox][disabled] + .lever:after,
-.switch label input[type=checkbox][disabled]:checked + .lever:after {
-  background-color: #BDBDBD;
-}
-
-/* Select Field
-   ========================================================================== */
-select {
-  display: none;
-}
-
-select.browser-default {
-  display: block;
-}
-
-select {
-  background-color: rgba(255, 255, 255, 0.9);
-  width: 100%;
-  padding: 5px;
-  border: 1px solid #f2f2f2;
-  border-radius: 2px;
-  height: 3rem;
-}
-
-.select-label {
-  position: absolute;
-}
-
-.select-wrapper {
-  position: relative;
-}
-
-.select-wrapper input.select-dropdown {
-  position: relative;
-  cursor: pointer;
-  background-color: transparent;
-  border: none;
-  border-bottom: 1px solid #9e9e9e;
-  outline: none;
-  height: 3rem;
-  line-height: 3rem;
-  width: 100%;
-  font-size: 1rem;
-  margin: 0 0 20px 0;
-  padding: 0;
-  display: block;
-}
-
-.select-wrapper span.caret {
-  color: initial;
-  position: absolute;
-  right: 0;
-  top: 0;
-  bottom: 0;
-  height: 10px;
-  margin: auto 0;
-  font-size: 10px;
-  line-height: 10px;
-}
-
-.select-wrapper span.caret.disabled {
-  color: rgba(0, 0, 0, 0.26);
-}
-
-.select-wrapper + label {
-  position: absolute;
-  top: -14px;
-  font-size: 0.8rem;
-}
-
-select:disabled {
-  color: rgba(0, 0, 0, 0.3);
-}
-
-.select-wrapper input.select-dropdown:disabled {
-  color: rgba(0, 0, 0, 0.3);
-  cursor: default;
-  -webkit-user-select: none;
-  /* webkit (safari, chrome) browsers */
-  -moz-user-select: none;
-  /* mozilla browsers */
-  -ms-user-select: none;
-  /* IE10+ */
-  border-bottom: 1px solid rgba(0, 0, 0, 0.3);
-}
-
-.select-wrapper i {
-  color: rgba(0, 0, 0, 0.3);
-}
-
-.select-dropdown li.disabled,
-.select-dropdown li.disabled > span,
-.select-dropdown li.optgroup {
-  color: rgba(0, 0, 0, 0.3);
-  background-color: transparent;
-}
-
-.prefix ~ .select-wrapper {
-  margin-left: 3rem;
-  width: 92%;
-  width: calc(100% - 3rem);
-}
-
-.prefix ~ label {
-  margin-left: 3rem;
-}
-
-.select-dropdown li img {
-  height: 40px;
-  width: 40px;
-  margin: 5px 15px;
-  float: right;
-}
-
-.select-dropdown li.optgroup {
-  border-top: 1px solid #eee;
-}
-
-.select-dropdown li.optgroup.selected > span {
-  color: rgba(0, 0, 0, 0.7);
-}
-
-.select-dropdown li.optgroup > span {
-  color: rgba(0, 0, 0, 0.4);
-}
-
-.select-dropdown li.optgroup ~ li.optgroup-option {
-  padding-left: 1rem;
-}
-
-/* File Input
-   ========================================================================== */
-.file-field {
-  position: relative;
-}
-
-.file-field .file-path-wrapper {
-  overflow: hidden;
-  padding-left: 10px;
-}
-
-.file-field input.file-path {
-  width: 100%;
-}
-
-.file-field .btn, .file-field .btn-large {
-  float: left;
-  height: 3rem;
-  line-height: 3rem;
-}
-
-.file-field span {
-  cursor: pointer;
-}
-
-.file-field input[type=file] {
-  position: absolute;
-  top: 0;
-  right: 0;
-  left: 0;
-  bottom: 0;
-  width: 100%;
-  margin: 0;
-  padding: 0;
-  font-size: 20px;
-  cursor: pointer;
-  opacity: 0;
-  filter: alpha(opacity=0);
-}
-
-/* Range
-   ========================================================================== */
-.range-field {
-  position: relative;
-}
-
-input[type=range],
-input[type=range] + .thumb {
-  cursor: pointer;
-}
-
-input[type=range] {
-  position: relative;
-  background-color: transparent;
-  border: none;
-  outline: none;
-  width: 100%;
-  margin: 15px 0;
-  padding: 0;
-}
-
-input[type=range]:focus {
-  outline: none;
-}
-
-input[type=range] + .thumb {
-  position: absolute;
-  border: none;
-  height: 0;
-  width: 0;
-  border-radius: 50%;
-  background-color: #26a69a;
-  top: 10px;
-  margin-left: -6px;
-  -webkit-transform-origin: 50% 50%;
-          transform-origin: 50% 50%;
-  -webkit-transform: rotate(-45deg);
-          transform: rotate(-45deg);
-}
-
-input[type=range] + .thumb .value {
-  display: block;
-  width: 30px;
-  text-align: center;
-  color: #26a69a;
-  font-size: 0;
-  -webkit-transform: rotate(45deg);
-          transform: rotate(45deg);
-}
-
-input[type=range] + .thumb.active {
-  border-radius: 50% 50% 50% 0;
-}
-
-input[type=range] + .thumb.active .value {
-  color: #fff;
-  margin-left: -1px;
-  margin-top: 8px;
-  font-size: 10px;
-}
-
-input[type=range] {
-  -webkit-appearance: none;
-}
-
-input[type=range]::-webkit-slider-runnable-track {
-  height: 3px;
-  background: #c2c0c2;
-  border: none;
-}
-
-input[type=range]::-webkit-slider-thumb {
-  -webkit-appearance: none;
-  border: none;
-  height: 14px;
-  width: 14px;
-  border-radius: 50%;
-  background-color: #26a69a;
-  -webkit-transform-origin: 50% 50%;
-          transform-origin: 50% 50%;
-  margin: -5px 0 0 0;
-  transition: .3s;
-}
-
-input[type=range]:focus::-webkit-slider-runnable-track {
-  background: #ccc;
-}
-
-input[type=range] {
-  /* fix for FF unable to apply focus style bug  */
-  border: 1px solid white;
-  /*required for proper track sizing in FF*/
-}
-
-input[type=range]::-moz-range-track {
-  height: 3px;
-  background: #ddd;
-  border: none;
-}
-
-input[type=range]::-moz-range-thumb {
-  border: none;
-  height: 14px;
-  width: 14px;
-  border-radius: 50%;
-  background: #26a69a;
-  margin-top: -5px;
-}
-
-input[type=range]:-moz-focusring {
-  outline: 1px solid #fff;
-  outline-offset: -1px;
-}
-
-input[type=range]:focus::-moz-range-track {
-  background: #ccc;
-}
-
-input[type=range]::-ms-track {
-  height: 3px;
-  background: transparent;
-  border-color: transparent;
-  border-width: 6px 0;
-  /*remove default tick marks*/
-  color: transparent;
-}
-
-input[type=range]::-ms-fill-lower {
-  background: #777;
-}
-
-input[type=range]::-ms-fill-upper {
-  background: #ddd;
-}
-
-input[type=range]::-ms-thumb {
-  border: none;
-  height: 14px;
-  width: 14px;
-  border-radius: 50%;
-  background: #26a69a;
-}
-
-input[type=range]:focus::-ms-fill-lower {
-  background: #888;
-}
-
-input[type=range]:focus::-ms-fill-upper {
-  background: #ccc;
-}
-
-/***************
-    Nav List
-***************/
-.table-of-contents.fixed {
-  position: fixed;
-}
-
-.table-of-contents li {
-  padding: 2px 0;
-}
-
-.table-of-contents a {
-  display: inline-block;
-  font-weight: 300;
-  color: #757575;
-  padding-left: 20px;
-  height: 1.5rem;
-  line-height: 1.5rem;
-  letter-spacing: .4;
-  display: inline-block;
-}
-
-.table-of-contents a:hover {
-  color: #a8a8a8;
-  padding-left: 19px;
-  border-left: 1px solid #ee6e73;
-}
-
-.table-of-contents a.active {
-  font-weight: 500;
-  padding-left: 18px;
-  border-left: 2px solid #ee6e73;
-}
-
-.side-nav {
-  position: fixed;
-  width: 300px;
-  left: 0;
-  top: 0;
-  margin: 0;
-  -webkit-transform: translateX(-100%);
-          transform: translateX(-100%);
-  height: 100%;
-  height: calc(100% + 60px);
-  height: -moz-calc(100%);
-  padding-bottom: 60px;
-  background-color: #fff;
-  z-index: 999;
-  overflow-y: auto;
-  will-change: transform;
-  -webkit-backface-visibility: hidden;
-          backface-visibility: hidden;
-  -webkit-transform: translateX(-105%);
-          transform: translateX(-105%);
-}
-
-.side-nav.right-aligned {
-  right: 0;
-  -webkit-transform: translateX(105%);
-          transform: translateX(105%);
-  left: auto;
-  -webkit-transform: translateX(100%);
-          transform: translateX(100%);
-}
-
-.side-nav .collapsible {
-  margin: 0;
-}
-
-.side-nav li {
-  float: none;
-  line-height: 48px;
-}
-
-.side-nav li.active {
-  background-color: rgba(0, 0, 0, 0.05);
-}
-
-.side-nav a {
-  color: rgba(0, 0, 0, 0.87);
-  display: block;
-  font-size: 14px;
-  font-weight: 500;
-  height: 48px;
-  line-height: 48px;
-  padding: 0 32px;
-}
-
-.side-nav a:hover {
-  background-color: rgba(0, 0, 0, 0.05);
-}
-
-.side-nav a.btn, .side-nav a.btn-large, .side-nav a.btn-large, .side-nav a.btn-flat, .side-nav a.btn-floating {
-  margin: 10px 15px;
-}
-
-.side-nav a.btn, .side-nav a.btn-large, .side-nav a.btn-large, .side-nav a.btn-floating {
-  color: #fff;
-}
-
-.side-nav a.btn-flat {
-  color: #343434;
-}
-
-.side-nav a.btn:hover, .side-nav a.btn-large:hover, .side-nav a.btn-large:hover {
-  background-color: #2bbbad;
-}
-
-.side-nav a.btn-floating:hover {
-  background-color: #26a69a;
-}
-
-.side-nav li > a > i,
-.side-nav li > a > [class^="mdi-"], .side-nav li > a > [class*="mdi-"],
-.side-nav li > a > i.material-icons {
-  float: left;
-  height: 48px;
-  line-height: 48px;
-  margin: 0 32px 0 0;
-  width: 24px;
-  color: rgba(0, 0, 0, 0.54);
-}
-
-.side-nav .divider {
-  margin: 8px 0 0 0;
-}
-
-.side-nav .subheader {
-  cursor: initial;
-  pointer-events: none;
-  color: rgba(0, 0, 0, 0.54);
-  font-size: 14px;
-  font-weight: 500;
-  line-height: 48px;
-}
-
-.side-nav .subheader:hover {
-  background-color: transparent;
-}
-
-.side-nav .userView {
-  position: relative;
-  padding: 32px 32px 0;
-  margin-bottom: 8px;
-}
-
-.side-nav .userView > a {
-  height: auto;
-  padding: 0;
-}
-
-.side-nav .userView > a:hover {
-  background-color: transparent;
-}
-
-.side-nav .userView .background {
-  overflow: hidden;
-  position: absolute;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: -1;
-}
-
-.side-nav .userView .circle, .side-nav .userView .name, .side-nav .userView .email {
-  display: block;
-}
-
-.side-nav .userView .circle {
-  height: 64px;
-  width: 64px;
-}
-
-.side-nav .userView .name,
-.side-nav .userView .email {
-  font-size: 14px;
-  line-height: 24px;
-}
-
-.side-nav .userView .name {
-  margin-top: 16px;
-  font-weight: 500;
-}
-
-.side-nav .userView .email {
-  padding-bottom: 16px;
-  font-weight: 400;
-}
-
-.drag-target {
-  height: 100%;
-  width: 10px;
-  position: fixed;
-  top: 0;
-  z-index: 998;
-}
-
-.side-nav.fixed {
-  left: 0;
-  -webkit-transform: translateX(0);
-          transform: translateX(0);
-  position: fixed;
-}
-
-.side-nav.fixed.right-aligned {
-  right: 0;
-  left: auto;
-}
-
-@media only screen and (max-width: 992px) {
-  .side-nav.fixed {
-    -webkit-transform: translateX(-105%);
-            transform: translateX(-105%);
-  }
-  .side-nav.fixed.right-aligned {
-    -webkit-transform: translateX(105%);
-            transform: translateX(105%);
-  }
-  .side-nav a {
-    padding: 0 16px;
-  }
-  .side-nav .userView {
-    padding: 16px 16px 0;
-  }
-}
-
-.side-nav .collapsible-body > ul:not(.collapsible) > li.active,
-.side-nav.fixed .collapsible-body > ul:not(.collapsible) > li.active {
-  background-color: #ee6e73;
-}
-
-.side-nav .collapsible-body > ul:not(.collapsible) > li.active a,
-.side-nav.fixed .collapsible-body > ul:not(.collapsible) > li.active a {
-  color: #fff;
-}
-
-#sidenav-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  height: 120vh;
-  background-color: rgba(0, 0, 0, 0.5);
-  z-index: 997;
-  will-change: opacity;
-}
-
-/*
-    @license
-    Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
-    This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-    The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-    The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-    Code distributed by Google as part of the polymer project is also
-    subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
- */
-/**************************/
-/* STYLES FOR THE SPINNER */
-/**************************/
-/*
- * Constants:
- *      STROKEWIDTH = 3px
- *      ARCSIZE     = 270 degrees (amount of circle the arc takes up)
- *      ARCTIME     = 1333ms (time it takes to expand and contract arc)
- *      ARCSTARTROT = 216 degrees (how much the start location of the arc
- *                                should rotate each time, 216 gives us a
- *                                5 pointed star shape (it's 360/5 * 3).
- *                                For a 7 pointed star, we might do
- *                                360/7 * 3 = 154.286)
- *      CONTAINERWIDTH = 28px
- *      SHRINK_TIME = 400ms
- */
-.preloader-wrapper {
-  display: inline-block;
-  position: relative;
-  width: 48px;
-  height: 48px;
-}
-
-.preloader-wrapper.small {
-  width: 36px;
-  height: 36px;
-}
-
-.preloader-wrapper.big {
-  width: 64px;
-  height: 64px;
-}
-
-.preloader-wrapper.active {
-  /* duration: 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
-  -webkit-animation: container-rotate 1568ms linear infinite;
-  animation: container-rotate 1568ms linear infinite;
-}
-
-@-webkit-keyframes container-rotate {
-  to {
-    -webkit-transform: rotate(360deg);
-  }
-}
-
-@keyframes container-rotate {
-  to {
-    -webkit-transform: rotate(360deg);
-            transform: rotate(360deg);
-  }
-}
-
-.spinner-layer {
-  position: absolute;
-  width: 100%;
-  height: 100%;
-  opacity: 0;
-  border-color: #26a69a;
-}
-
-.spinner-blue,
-.spinner-blue-only {
-  border-color: #4285f4;
-}
-
-.spinner-red,
-.spinner-red-only {
-  border-color: #db4437;
-}
-
-.spinner-yellow,
-.spinner-yellow-only {
-  border-color: #f4b400;
-}
-
-.spinner-green,
-.spinner-green-only {
-  border-color: #0f9d58;
-}
-
-/**
- * IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee):
- *
- * iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't
- * guarantee that the animation will start _exactly_ after that value. So we avoid using
- * animation-delay and instead set custom keyframes for each color (as redundant as it
- * seems).
- *
- * We write out each animation in full (instead of separating animation-name,
- * animation-duration, etc.) because under the polyfill, Safari does not recognize those
- * specific properties properly, treats them as -webkit-animation, and overrides the
- * other animation rules. See https://github.com/Polymer/platform/issues/53.
- */
-.active .spinner-layer.spinner-blue {
-  /* durations: 4 * ARCTIME */
-  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-}
-
-.active .spinner-layer.spinner-red {
-  /* durations: 4 * ARCTIME */
-  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-}
-
-.active .spinner-layer.spinner-yellow {
-  /* durations: 4 * ARCTIME */
-  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-}
-
-.active .spinner-layer.spinner-green {
-  /* durations: 4 * ARCTIME */
-  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-}
-
-.active .spinner-layer,
-.active .spinner-layer.spinner-blue-only,
-.active .spinner-layer.spinner-red-only,
-.active .spinner-layer.spinner-yellow-only,
-.active .spinner-layer.spinner-green-only {
-  /* durations: 4 * ARCTIME */
-  opacity: 1;
-  -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-  animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-}
-
-@-webkit-keyframes fill-unfill-rotate {
-  12.5% {
-    -webkit-transform: rotate(135deg);
-  }
-  /* 0.5 * ARCSIZE */
-  25% {
-    -webkit-transform: rotate(270deg);
-  }
-  /* 1   * ARCSIZE */
-  37.5% {
-    -webkit-transform: rotate(405deg);
-  }
-  /* 1.5 * ARCSIZE */
-  50% {
-    -webkit-transform: rotate(540deg);
-  }
-  /* 2   * ARCSIZE */
-  62.5% {
-    -webkit-transform: rotate(675deg);
-  }
-  /* 2.5 * ARCSIZE */
-  75% {
-    -webkit-transform: rotate(810deg);
-  }
-  /* 3   * ARCSIZE */
-  87.5% {
-    -webkit-transform: rotate(945deg);
-  }
-  /* 3.5 * ARCSIZE */
-  to {
-    -webkit-transform: rotate(1080deg);
-  }
-  /* 4   * ARCSIZE */
-}
-
-@keyframes fill-unfill-rotate {
-  12.5% {
-    -webkit-transform: rotate(135deg);
-            transform: rotate(135deg);
-  }
-  /* 0.5 * ARCSIZE */
-  25% {
-    -webkit-transform: rotate(270deg);
-            transform: rotate(270deg);
-  }
-  /* 1   * ARCSIZE */
-  37.5% {
-    -webkit-transform: rotate(405deg);
-            transform: rotate(405deg);
-  }
-  /* 1.5 * ARCSIZE */
-  50% {
-    -webkit-transform: rotate(540deg);
-            transform: rotate(540deg);
-  }
-  /* 2   * ARCSIZE */
-  62.5% {
-    -webkit-transform: rotate(675deg);
-            transform: rotate(675deg);
-  }
-  /* 2.5 * ARCSIZE */
-  75% {
-    -webkit-transform: rotate(810deg);
-            transform: rotate(810deg);
-  }
-  /* 3   * ARCSIZE */
-  87.5% {
-    -webkit-transform: rotate(945deg);
-            transform: rotate(945deg);
-  }
-  /* 3.5 * ARCSIZE */
-  to {
-    -webkit-transform: rotate(1080deg);
-            transform: rotate(1080deg);
-  }
-  /* 4   * ARCSIZE */
-}
-
-@-webkit-keyframes blue-fade-in-out {
-  from {
-    opacity: 1;
-  }
-  25% {
-    opacity: 1;
-  }
-  26% {
-    opacity: 0;
-  }
-  89% {
-    opacity: 0;
-  }
-  90% {
-    opacity: 1;
-  }
-  100% {
-    opacity: 1;
-  }
-}
-
-@keyframes blue-fade-in-out {
-  from {
-    opacity: 1;
-  }
-  25% {
-    opacity: 1;
-  }
-  26% {
-    opacity: 0;
-  }
-  89% {
-    opacity: 0;
-  }
-  90% {
-    opacity: 1;
-  }
-  100% {
-    opacity: 1;
-  }
-}
-
-@-webkit-keyframes red-fade-in-out {
-  from {
-    opacity: 0;
-  }
-  15% {
-    opacity: 0;
-  }
-  25% {
-    opacity: 1;
-  }
-  50% {
-    opacity: 1;
-  }
-  51% {
-    opacity: 0;
-  }
-}
-
-@keyframes red-fade-in-out {
-  from {
-    opacity: 0;
-  }
-  15% {
-    opacity: 0;
-  }
-  25% {
-    opacity: 1;
-  }
-  50% {
-    opacity: 1;
-  }
-  51% {
-    opacity: 0;
-  }
-}
-
-@-webkit-keyframes yellow-fade-in-out {
-  from {
-    opacity: 0;
-  }
-  40% {
-    opacity: 0;
-  }
-  50% {
-    opacity: 1;
-  }
-  75% {
-    opacity: 1;
-  }
-  76% {
-    opacity: 0;
-  }
-}
-
-@keyframes yellow-fade-in-out {
-  from {
-    opacity: 0;
-  }
-  40% {
-    opacity: 0;
-  }
-  50% {
-    opacity: 1;
-  }
-  75% {
-    opacity: 1;
-  }
-  76% {
-    opacity: 0;
-  }
-}
-
-@-webkit-keyframes green-fade-in-out {
-  from {
-    opacity: 0;
-  }
-  65% {
-    opacity: 0;
-  }
-  75% {
-    opacity: 1;
-  }
-  90% {
-    opacity: 1;
-  }
-  100% {
-    opacity: 0;
-  }
-}
-
-@keyframes green-fade-in-out {
-  from {
-    opacity: 0;
-  }
-  65% {
-    opacity: 0;
-  }
-  75% {
-    opacity: 1;
-  }
-  90% {
-    opacity: 1;
-  }
-  100% {
-    opacity: 0;
-  }
-}
-
-/**
- * Patch the gap that appear between the two adjacent div.circle-clipper while the
- * spinner is rotating (appears on Chrome 38, Safari 7.1, and IE 11).
- */
-.gap-patch {
-  position: absolute;
-  top: 0;
-  left: 45%;
-  width: 10%;
-  height: 100%;
-  overflow: hidden;
-  border-color: inherit;
-}
-
-.gap-patch .circle {
-  width: 1000%;
-  left: -450%;
-}
-
-.circle-clipper {
-  display: inline-block;
-  position: relative;
-  width: 50%;
-  height: 100%;
-  overflow: hidden;
-  border-color: inherit;
-}
-
-.circle-clipper .circle {
-  width: 200%;
-  height: 100%;
-  border-width: 3px;
-  /* STROKEWIDTH */
-  border-style: solid;
-  border-color: inherit;
-  border-bottom-color: transparent !important;
-  border-radius: 50%;
-  -webkit-animation: none;
-  animation: none;
-  position: absolute;
-  top: 0;
-  right: 0;
-  bottom: 0;
-}
-
-.circle-clipper.left .circle {
-  left: 0;
-  border-right-color: transparent !important;
-  -webkit-transform: rotate(129deg);
-  transform: rotate(129deg);
-}
-
-.circle-clipper.right .circle {
-  left: -100%;
-  border-left-color: transparent !important;
-  -webkit-transform: rotate(-129deg);
-  transform: rotate(-129deg);
-}
-
-.active .circle-clipper.left .circle {
-  /* duration: ARCTIME */
-  -webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-  animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-}
-
-.active .circle-clipper.right .circle {
-  /* duration: ARCTIME */
-  -webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-  animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
-}
-
-@-webkit-keyframes left-spin {
-  from {
-    -webkit-transform: rotate(130deg);
-  }
-  50% {
-    -webkit-transform: rotate(-5deg);
-  }
-  to {
-    -webkit-transform: rotate(130deg);
-  }
-}
-
-@keyframes left-spin {
-  from {
-    -webkit-transform: rotate(130deg);
-            transform: rotate(130deg);
-  }
-  50% {
-    -webkit-transform: rotate(-5deg);
-            transform: rotate(-5deg);
-  }
-  to {
-    -webkit-transform: rotate(130deg);
-            transform: rotate(130deg);
-  }
-}
-
-@-webkit-keyframes right-spin {
-  from {
-    -webkit-transform: rotate(-130deg);
-  }
-  50% {
-    -webkit-transform: rotate(5deg);
-  }
-  to {
-    -webkit-transform: rotate(-130deg);
-  }
-}
-
-@keyframes right-spin {
-  from {
-    -webkit-transform: rotate(-130deg);
-            transform: rotate(-130deg);
-  }
-  50% {
-    -webkit-transform: rotate(5deg);
-            transform: rotate(5deg);
-  }
-  to {
-    -webkit-transform: rotate(-130deg);
-            transform: rotate(-130deg);
-  }
-}
-
-#spinnerContainer.cooldown {
-  /* duration: SHRINK_TIME */
-  -webkit-animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1);
-  animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1);
-}
-
-@-webkit-keyframes fade-out {
-  from {
-    opacity: 1;
-  }
-  to {
-    opacity: 0;
-  }
-}
-
-@keyframes fade-out {
-  from {
-    opacity: 1;
-  }
-  to {
-    opacity: 0;
-  }
-}
-
-.slider {
-  position: relative;
-  height: 400px;
-  width: 100%;
-}
-
-.slider.fullscreen {
-  height: 100%;
-  width: 100%;
-  position: absolute;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-}
-
-.slider.fullscreen ul.slides {
-  height: 100%;
-}
-
-.slider.fullscreen ul.indicators {
-  z-index: 2;
-  bottom: 30px;
-}
-
-.slider .slides {
-  background-color: #9e9e9e;
-  margin: 0;
-  height: 400px;
-}
-
-.slider .slides li {
-  opacity: 0;
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1;
-  width: 100%;
-  height: inherit;
-  overflow: hidden;
-}
-
-.slider .slides li img {
-  height: 100%;
-  width: 100%;
-  background-size: cover;
-  background-position: center;
-}
-
-.slider .slides li .caption {
-  color: #fff;
-  position: absolute;
-  top: 15%;
-  left: 15%;
-  width: 70%;
-  opacity: 0;
-}
-
-.slider .slides li .caption p {
-  color: #e0e0e0;
-}
-
-.slider .slides li.active {
-  z-index: 2;
-}
-
-.slider .indicators {
-  position: absolute;
-  text-align: center;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  margin: 0;
-}
-
-.slider .indicators .indicator-item {
-  display: inline-block;
-  position: relative;
-  cursor: pointer;
-  height: 16px;
-  width: 16px;
-  margin: 0 12px;
-  background-color: #e0e0e0;
-  transition: background-color .3s;
-  border-radius: 50%;
-}
-
-.slider .indicators .indicator-item.active {
-  background-color: #4CAF50;
-}
-
-.carousel {
-  overflow: hidden;
-  position: relative;
-  width: 100%;
-  height: 400px;
-  -webkit-perspective: 500px;
-          perspective: 500px;
-  -webkit-transform-style: preserve-3d;
-          transform-style: preserve-3d;
-  -webkit-transform-origin: 0% 50%;
-          transform-origin: 0% 50%;
-}
-
-.carousel.carousel-slider {
-  top: 0;
-  left: 0;
-  height: 0;
-}
-
-.carousel.carousel-slider .carousel-fixed-item {
-  position: absolute;
-  left: 0;
-  right: 0;
-  bottom: 20px;
-  z-index: 1;
-}
-
-.carousel.carousel-slider .carousel-fixed-item.with-indicators {
-  bottom: 68px;
-}
-
-.carousel.carousel-slider .carousel-item {
-  width: 100%;
-  height: 100%;
-  min-height: 400px;
-  position: absolute;
-  top: 0;
-  left: 0;
-}
-
-.carousel.carousel-slider .carousel-item h2 {
-  font-size: 24px;
-  font-weight: 500;
-  line-height: 32px;
-}
-
-.carousel.carousel-slider .carousel-item p {
-  font-size: 15px;
-}
-
-.carousel .carousel-item {
-  display: none;
-  width: 200px;
-  height: 200px;
-  position: absolute;
-  top: 0;
-  left: 0;
-}
-
-.carousel .carousel-item img {
-  width: 100%;
-}
-
-.carousel .indicators {
-  position: absolute;
-  text-align: center;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  margin: 0;
-}
-
-.carousel .indicators .indicator-item {
-  display: inline-block;
-  position: relative;
-  cursor: pointer;
-  height: 8px;
-  width: 8px;
-  margin: 24px 4px;
-  background-color: rgba(255, 255, 255, 0.5);
-  transition: background-color .3s;
-  border-radius: 50%;
-}
-
-.carousel .indicators .indicator-item.active {
-  background-color: #fff;
-}
-
-/* ==========================================================================
-   $BASE-PICKER
-   ========================================================================== */
-/**
- * Note: the root picker element should *NOT* be styled more than what's here.
- */
-.picker {
-  font-size: 16px;
-  text-align: left;
-  line-height: 1.2;
-  color: #000000;
-  position: absolute;
-  z-index: 10000;
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-  user-select: none;
-}
-
-/**
- * The picker input element.
- */
-.picker__input {
-  cursor: default;
-}
-
-/**
- * When the picker is opened, the input element is "activated".
- */
-.picker__input.picker__input--active {
-  border-color: #0089ec;
-}
-
-/**
- * The holder is the only "scrollable" top-level container element.
- */
-.picker__holder {
-  width: 100%;
-  overflow-y: auto;
-  -webkit-overflow-scrolling: touch;
-}
-
-/*!
- * Default mobile-first, responsive styling for pickadate.js
- * Demo: http://amsul.github.io/pickadate.js
- */
-/**
- * Note: the root picker element should *NOT* be styled more than what's here.
- */
-/**
- * Make the holder and frame fullscreen.
- */
-.picker__holder,
-.picker__frame {
-  bottom: 0;
-  left: 0;
-  right: 0;
-  top: 100%;
-}
-
-/**
- * The holder should overlay the entire screen.
- */
-.picker__holder {
-  position: fixed;
-  transition: background 0.15s ease-out, top 0s 0.15s;
-  -webkit-backface-visibility: hidden;
-}
-
-/**
- * The frame that bounds the box contents of the picker.
- */
-.picker__frame {
-  position: absolute;
-  margin: 0 auto;
-  min-width: 256px;
-  width: 300px;
-  max-height: 350px;
-  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
-  filter: alpha(opacity=0);
-  -moz-opacity: 0;
-  opacity: 0;
-  transition: all 0.15s ease-out;
-}
-
-@media (min-height: 28.875em) {
-  .picker__frame {
-    overflow: visible;
-    top: auto;
-    bottom: -100%;
-    max-height: 80%;
-  }
-}
-
-@media (min-height: 40.125em) {
-  .picker__frame {
-    margin-bottom: 7.5%;
-  }
-}
-
-/**
- * The wrapper sets the stage to vertically align the box contents.
- */
-.picker__wrap {
-  display: table;
-  width: 100%;
-  height: 100%;
-}
-
-@media (min-height: 28.875em) {
-  .picker__wrap {
-    display: block;
-  }
-}
-
-/**
- * The box contains all the picker contents.
- */
-.picker__box {
-  background: #ffffff;
-  display: table-cell;
-  vertical-align: middle;
-}
-
-@media (min-height: 28.875em) {
-  .picker__box {
-    display: block;
-    border: 1px solid #777777;
-    border-top-color: #898989;
-    border-bottom-width: 0;
-    border-radius: 5px 5px 0 0;
-    box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24);
-  }
-}
-
-/**
- * When the picker opens...
- */
-.picker--opened .picker__holder {
-  top: 0;
-  background: transparent;
-  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E000000,endColorstr=#1E000000)";
-  zoom: 1;
-  background: rgba(0, 0, 0, 0.32);
-  transition: background 0.15s ease-out;
-}
-
-.picker--opened .picker__frame {
-  top: 0;
-  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
-  filter: alpha(opacity=100);
-  -moz-opacity: 1;
-  opacity: 1;
-}
-
-@media (min-height: 35.875em) {
-  .picker--opened .picker__frame {
-    top: 10%;
-    bottom: auto;
-  }
-}
-
-/**
- * For `large` screens, transform into an inline picker.
- */
-/* ==========================================================================
-   CUSTOM MATERIALIZE STYLES
-   ========================================================================== */
-.picker__input.picker__input--active {
-  border-color: #E3F2FD;
-}
-
-.picker__frame {
-  margin: 0 auto;
-  max-width: 325px;
-}
-
-@media (min-height: 38.875em) {
-  .picker--opened .picker__frame {
-    top: 10%;
-    bottom: auto;
-  }
-}
-
-/* ==========================================================================
-   $BASE-DATE-PICKER
-   ========================================================================== */
-/**
- * The picker box.
- */
-.picker__box {
-  padding: 0 1em;
-}
-
-/**
- * The header containing the month and year stuff.
- */
-.picker__header {
-  text-align: center;
-  position: relative;
-  margin-top: .75em;
-}
-
-/**
- * The month and year labels.
- */
-.picker__month,
-.picker__year {
-  display: inline-block;
-  margin-left: .25em;
-  margin-right: .25em;
-}
-
-/**
- * The month and year selectors.
- */
-.picker__select--month,
-.picker__select--year {
-  height: 2em;
-  padding: 0;
-  margin-left: .25em;
-  margin-right: .25em;
-}
-
-.picker__select--month.browser-default {
-  display: inline;
-  background-color: #FFFFFF;
-  width: 40%;
-}
-
-.picker__select--year.browser-default {
-  display: inline;
-  background-color: #FFFFFF;
-  width: 26%;
-}
-
-.picker__select--month:focus,
-.picker__select--year:focus {
-  border-color: rgba(0, 0, 0, 0.05);
-}
-
-/**
- * The month navigation buttons.
- */
-.picker__nav--prev,
-.picker__nav--next {
-  position: absolute;
-  padding: .5em 1.25em;
-  width: 1em;
-  height: 1em;
-  box-sizing: content-box;
-  top: -0.25em;
-}
-
-.picker__nav--prev {
-  left: -1em;
-  padding-right: 1.25em;
-}
-
-.picker__nav--next {
-  right: -1em;
-  padding-left: 1.25em;
-}
-
-.picker__nav--disabled,
-.picker__nav--disabled:hover,
-.picker__nav--disabled:before,
-.picker__nav--disabled:before:hover {
-  cursor: default;
-  background: none;
-  border-right-color: #f5f5f5;
-  border-left-color: #f5f5f5;
-}
-
-/**
- * The calendar table of dates
- */
-.picker__table {
-  text-align: center;
-  border-collapse: collapse;
-  border-spacing: 0;
-  table-layout: fixed;
-  font-size: 1rem;
-  width: 100%;
-  margin-top: .75em;
-  margin-bottom: .5em;
-}
-
-.picker__table th, .picker__table td {
-  text-align: center;
-}
-
-.picker__table td {
-  margin: 0;
-  padding: 0;
-}
-
-/**
- * The weekday labels
- */
-.picker__weekday {
-  width: 14.285714286%;
-  font-size: .75em;
-  padding-bottom: .25em;
-  color: #999999;
-  font-weight: 500;
-  /* Increase the spacing a tad */
-}
-
-@media (min-height: 33.875em) {
-  .picker__weekday {
-    padding-bottom: .5em;
-  }
-}
-
-/**
- * The days on the calendar
- */
-.picker__day--today {
-  position: relative;
-  color: #595959;
-  letter-spacing: -.3;
-  padding: .75rem 0;
-  font-weight: 400;
-  border: 1px solid transparent;
-}
-
-.picker__day--disabled:before {
-  border-top-color: #aaaaaa;
-}
-
-.picker__day--infocus:hover {
-  cursor: pointer;
-  color: #000;
-  font-weight: 500;
-}
-
-.picker__day--outfocus {
-  display: none;
-  padding: .75rem 0;
-  color: #fff;
-}
-
-.picker__day--outfocus:hover {
-  cursor: pointer;
-  color: #dddddd;
-  font-weight: 500;
-}
-
-.picker__day--highlighted:hover,
-.picker--focused .picker__day--highlighted {
-  cursor: pointer;
-}
-
-.picker__day--selected,
-.picker__day--selected:hover,
-.picker--focused .picker__day--selected {
-  border-radius: 50%;
-  -webkit-transform: scale(0.75);
-          transform: scale(0.75);
-  background: #0089ec;
-  color: #ffffff;
-}
-
-.picker__day--disabled,
-.picker__day--disabled:hover,
-.picker--focused .picker__day--disabled {
-  background: #f5f5f5;
-  border-color: #f5f5f5;
-  color: #dddddd;
-  cursor: default;
-}
-
-.picker__day--highlighted.picker__day--disabled,
-.picker__day--highlighted.picker__day--disabled:hover {
-  background: #bbbbbb;
-}
-
-/**
- * The footer containing the "today", "clear", and "close" buttons.
- */
-.picker__footer {
-  text-align: center;
-  display: -webkit-flex;
-  display: -ms-flexbox;
-  display: flex;
-  -webkit-align-items: center;
-      -ms-flex-align: center;
-          align-items: center;
-  -webkit-justify-content: space-between;
-      -ms-flex-pack: justify;
-          justify-content: space-between;
-}
-
-.picker__button--today,
-.picker__button--clear,
-.picker__button--close {
-  border: 1px solid #ffffff;
-  background: #ffffff;
-  font-size: .8em;
-  padding: .66em 0;
-  font-weight: bold;
-  width: 33%;
-  display: inline-block;
-  vertical-align: bottom;
-}
-
-.picker__button--today:hover,
-.picker__button--clear:hover,
-.picker__button--close:hover {
-  cursor: pointer;
-  color: #000000;
-  background: #b1dcfb;
-  border-bottom-color: #b1dcfb;
-}
-
-.picker__button--today:focus,
-.picker__button--clear:focus,
-.picker__button--close:focus {
-  background: #b1dcfb;
-  border-color: rgba(0, 0, 0, 0.05);
-  outline: none;
-}
-
-.picker__button--today:before,
-.picker__button--clear:before,
-.picker__button--close:before {
-  position: relative;
-  display: inline-block;
-  height: 0;
-}
-
-.picker__button--today:before,
-.picker__button--clear:before {
-  content: " ";
-  margin-right: .45em;
-}
-
-.picker__button--today:before {
-  top: -0.05em;
-  width: 0;
-  border-top: 0.66em solid #0059bc;
-  border-left: .66em solid transparent;
-}
-
-.picker__button--clear:before {
-  top: -0.25em;
-  width: .66em;
-  border-top: 3px solid #ee2200;
-}
-
-.picker__button--close:before {
-  content: "\D7";
-  top: -0.1em;
-  vertical-align: top;
-  font-size: 1.1em;
-  margin-right: .35em;
-  color: #777777;
-}
-
-.picker__button--today[disabled],
-.picker__button--today[disabled]:hover {
-  background: #f5f5f5;
-  border-color: #f5f5f5;
-  color: #dddddd;
-  cursor: default;
-}
-
-.picker__button--today[disabled]:before {
-  border-top-color: #aaaaaa;
-}
-
-/* ==========================================================================
-   CUSTOM MATERIALIZE STYLES
-   ========================================================================== */
-.picker__box {
-  border-radius: 2px;
-  overflow: hidden;
-}
-
-.picker__date-display {
-  text-align: center;
-  background-color: #26a69a;
-  color: #fff;
-  padding-bottom: 15px;
-  font-weight: 300;
-}
-
-.picker__nav--prev:hover,
-.picker__nav--next:hover {
-  cursor: pointer;
-  color: #000000;
-  background: #a1ded8;
-}
-
-.picker__weekday-display {
-  background-color: #1f897f;
-  padding: 10px;
-  font-weight: 200;
-  letter-spacing: .5;
-  font-size: 1rem;
-  margin-bottom: 15px;
-}
-
-.picker__month-display {
-  text-transform: uppercase;
-  font-size: 2rem;
-}
-
-.picker__day-display {
-  font-size: 4.5rem;
-  font-weight: 400;
-}
-
-.picker__year-display {
-  font-size: 1.8rem;
-  color: rgba(255, 255, 255, 0.4);
-}
-
-.picker__box {
-  padding: 0;
-}
-
-.picker__calendar-container {
-  padding: 0 1rem;
-}
-
-.picker__calendar-container thead {
-  border: none;
-}
-
-.picker__table {
-  margin-top: 0;
-  margin-bottom: .5em;
-}
-
-.picker__day--infocus {
-  color: #595959;
-  letter-spacing: -.3;
-  padding: .75rem 0;
-  font-weight: 400;
-  border: 1px solid transparent;
-}
-
-.picker__day.picker__day--today {
-  color: #26a69a;
-}
-
-.picker__day.picker__day--today.picker__day--selected {
-  color: #fff;
-}
-
-.picker__weekday {
-  font-size: .9rem;
-}
-
-.picker__day--selected,
-.picker__day--selected:hover,
-.picker--focused .picker__day--selected {
-  border-radius: 50%;
-  -webkit-transform: scale(0.9);
-          transform: scale(0.9);
-  background-color: #26a69a;
-  color: #ffffff;
-}
-
-.picker__day--selected.picker__day--outfocus,
-.picker__day--selected:hover.picker__day--outfocus,
-.picker--focused .picker__day--selected.picker__day--outfocus {
-  background-color: #a1ded8;
-}
-
-.picker__footer {
-  text-align: right;
-  padding: 5px 10px;
-}
-
-.picker__close, .picker__today {
-  font-size: 1.1rem;
-  padding: 0 1rem;
-  color: #26a69a;
-}
-
-.picker__nav--prev:before,
-.picker__nav--next:before {
-  content: " ";
-  border-top: .5em solid transparent;
-  border-bottom: .5em solid transparent;
-  border-right: 0.75em solid #676767;
-  width: 0;
-  height: 0;
-  display: block;
-  margin: 0 auto;
-}
-
-.picker__nav--next:before {
-  border-right: 0;
-  border-left: 0.75em solid #676767;
-}
-
-button.picker__today:focus, button.picker__clear:focus, button.picker__close:focus {
-  background-color: #a1ded8;
-}
-
-/* ==========================================================================
-   $BASE-TIME-PICKER
-   ========================================================================== */
-/**
- * The list of times.
- */
-.picker__list {
-  list-style: none;
-  padding: 0.75em 0 4.2em;
-  margin: 0;
-}
-
-/**
- * The times on the clock.
- */
-.picker__list-item {
-  border-bottom: 1px solid #dddddd;
-  border-top: 1px solid #dddddd;
-  margin-bottom: -1px;
-  position: relative;
-  background: #ffffff;
-  padding: .75em 1.25em;
-}
-
-@media (min-height: 46.75em) {
-  .picker__list-item {
-    padding: .5em 1em;
-  }
-}
-
-/* Hovered time */
-.picker__list-item:hover {
-  cursor: pointer;
-  color: #000000;
-  background: #b1dcfb;
-  border-color: #0089ec;
-  z-index: 10;
-}
-
-/* Highlighted and hovered/focused time */
-.picker__list-item--highlighted {
-  border-color: #0089ec;
-  z-index: 10;
-}
-
-.picker__list-item--highlighted:hover,
-.picker--focused .picker__list-item--highlighted {
-  cursor: pointer;
-  color: #000000;
-  background: #b1dcfb;
-}
-
-/* Selected and hovered/focused time */
-.picker__list-item--selected,
-.picker__list-item--selected:hover,
-.picker--focused .picker__list-item--selected {
-  background: #0089ec;
-  color: #ffffff;
-  z-index: 10;
-}
-
-/* Disabled time */
-.picker__list-item--disabled,
-.picker__list-item--disabled:hover,
-.picker--focused .picker__list-item--disabled {
-  background: #f5f5f5;
-  border-color: #f5f5f5;
-  color: #dddddd;
-  cursor: default;
-  border-color: #dddddd;
-  z-index: auto;
-}
-
-/**
- * The clear button
- */
-.picker--time .picker__button--clear {
-  display: block;
-  width: 80%;
-  margin: 1em auto 0;
-  padding: 1em 1.25em;
-  background: none;
-  border: 0;
-  font-weight: 500;
-  font-size: .67em;
-  text-align: center;
-  text-transform: uppercase;
-  color: #666;
-}
-
-.picker--time .picker__button--clear:hover,
-.picker--time .picker__button--clear:focus {
-  color: #000000;
-  background: #b1dcfb;
-  background: #ee2200;
-  border-color: #ee2200;
-  cursor: pointer;
-  color: #ffffff;
-  outline: none;
-}
-
-.picker--time .picker__button--clear:before {
-  top: -0.25em;
-  color: #666;
-  font-size: 1.25em;
-  font-weight: bold;
-}
-
-.picker--time .picker__button--clear:hover:before,
-.picker--time .picker__button--clear:focus:before {
-  color: #ffffff;
-}
-
-/* ==========================================================================
-   $DEFAULT-TIME-PICKER
-   ========================================================================== */
-/**
- * The frame the bounds the time picker.
- */
-.picker--time .picker__frame {
-  min-width: 256px;
-  max-width: 320px;
-}
-
-/**
- * The picker box.
- */
-.picker--time .picker__box {
-  font-size: 1em;
-  background: #f2f2f2;
-  padding: 0;
-}
-
-@media (min-height: 40.125em) {
-  .picker--time .picker__box {
-    margin-bottom: 5em;
-  }
-}
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/css/materialize.min.css b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/css/materialize.min.css
deleted file mode 100644 (file)
index 9104745..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*!
- * Materialize v0.98.0 (http://materializecss.com)
- * Copyright 2014-2015 Materialize
- * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE)
- */
-.materialize-red{background-color:#e51c23 !important}.materialize-red-text{color:#e51c23 !important}.materialize-red.lighten-5{background-color:#fdeaeb !important}.materialize-red-text.text-lighten-5{color:#fdeaeb !important}.materialize-red.lighten-4{background-color:#f8c1c3 !important}.materialize-red-text.text-lighten-4{color:#f8c1c3 !important}.materialize-red.lighten-3{background-color:#f3989b !important}.materialize-red-text.text-lighten-3{color:#f3989b !important}.materialize-red.lighten-2{background-color:#ee6e73 !important}.materialize-red-text.text-lighten-2{color:#ee6e73 !important}.materialize-red.lighten-1{background-color:#ea454b !important}.materialize-red-text.text-lighten-1{color:#ea454b !important}.materialize-red.darken-1{background-color:#d0181e !important}.materialize-red-text.text-darken-1{color:#d0181e !important}.materialize-red.darken-2{background-color:#b9151b !important}.materialize-red-text.text-darken-2{color:#b9151b !important}.materialize-red.darken-3{background-color:#a21318 !important}.materialize-red-text.text-darken-3{color:#a21318 !important}.materialize-red.darken-4{background-color:#8b1014 !important}.materialize-red-text.text-darken-4{color:#8b1014 !important}.red{background-color:#F44336 !important}.red-text{color:#F44336 !important}.red.lighten-5{background-color:#FFEBEE !important}.red-text.text-lighten-5{color:#FFEBEE !important}.red.lighten-4{background-color:#FFCDD2 !important}.red-text.text-lighten-4{color:#FFCDD2 !important}.red.lighten-3{background-color:#EF9A9A !important}.red-text.text-lighten-3{color:#EF9A9A !important}.red.lighten-2{background-color:#E57373 !important}.red-text.text-lighten-2{color:#E57373 !important}.red.lighten-1{background-color:#EF5350 !important}.red-text.text-lighten-1{color:#EF5350 !important}.red.darken-1{background-color:#E53935 !important}.red-text.text-darken-1{color:#E53935 !important}.red.darken-2{background-color:#D32F2F !important}.red-text.text-darken-2{color:#D32F2F !important}.red.darken-3{background-color:#C62828 !important}.red-text.text-darken-3{color:#C62828 !important}.red.darken-4{background-color:#B71C1C !important}.red-text.text-darken-4{color:#B71C1C !important}.red.accent-1{background-color:#FF8A80 !important}.red-text.text-accent-1{color:#FF8A80 !important}.red.accent-2{background-color:#FF5252 !important}.red-text.text-accent-2{color:#FF5252 !important}.red.accent-3{background-color:#FF1744 !important}.red-text.text-accent-3{color:#FF1744 !important}.red.accent-4{background-color:#D50000 !important}.red-text.text-accent-4{color:#D50000 !important}.pink{background-color:#e91e63 !important}.pink-text{color:#e91e63 !important}.pink.lighten-5{background-color:#fce4ec !important}.pink-text.text-lighten-5{color:#fce4ec !important}.pink.lighten-4{background-color:#f8bbd0 !important}.pink-text.text-lighten-4{color:#f8bbd0 !important}.pink.lighten-3{background-color:#f48fb1 !important}.pink-text.text-lighten-3{color:#f48fb1 !important}.pink.lighten-2{background-color:#f06292 !important}.pink-text.text-lighten-2{color:#f06292 !important}.pink.lighten-1{background-color:#ec407a !important}.pink-text.text-lighten-1{color:#ec407a !important}.pink.darken-1{background-color:#d81b60 !important}.pink-text.text-darken-1{color:#d81b60 !important}.pink.darken-2{background-color:#c2185b !important}.pink-text.text-darken-2{color:#c2185b !important}.pink.darken-3{background-color:#ad1457 !important}.pink-text.text-darken-3{color:#ad1457 !important}.pink.darken-4{background-color:#880e4f !important}.pink-text.text-darken-4{color:#880e4f !important}.pink.accent-1{background-color:#ff80ab !important}.pink-text.text-accent-1{color:#ff80ab !important}.pink.accent-2{background-color:#ff4081 !important}.pink-text.text-accent-2{color:#ff4081 !important}.pink.accent-3{background-color:#f50057 !important}.pink-text.text-accent-3{color:#f50057 !important}.pink.accent-4{background-color:#c51162 !important}.pink-text.text-accent-4{color:#c51162 !important}.purple{background-color:#9c27b0 !important}.purple-text{color:#9c27b0 !important}.purple.lighten-5{background-color:#f3e5f5 !important}.purple-text.text-lighten-5{color:#f3e5f5 !important}.purple.lighten-4{background-color:#e1bee7 !important}.purple-text.text-lighten-4{color:#e1bee7 !important}.purple.lighten-3{background-color:#ce93d8 !important}.purple-text.text-lighten-3{color:#ce93d8 !important}.purple.lighten-2{background-color:#ba68c8 !important}.purple-text.text-lighten-2{color:#ba68c8 !important}.purple.lighten-1{background-color:#ab47bc !important}.purple-text.text-lighten-1{color:#ab47bc !important}.purple.darken-1{background-color:#8e24aa !important}.purple-text.text-darken-1{color:#8e24aa !important}.purple.darken-2{background-color:#7b1fa2 !important}.purple-text.text-darken-2{color:#7b1fa2 !important}.purple.darken-3{background-color:#6a1b9a !important}.purple-text.text-darken-3{color:#6a1b9a !important}.purple.darken-4{background-color:#4a148c !important}.purple-text.text-darken-4{color:#4a148c !important}.purple.accent-1{background-color:#ea80fc !important}.purple-text.text-accent-1{color:#ea80fc !important}.purple.accent-2{background-color:#e040fb !important}.purple-text.text-accent-2{color:#e040fb !important}.purple.accent-3{background-color:#d500f9 !important}.purple-text.text-accent-3{color:#d500f9 !important}.purple.accent-4{background-color:#a0f !important}.purple-text.text-accent-4{color:#a0f !important}.deep-purple{background-color:#673ab7 !important}.deep-purple-text{color:#673ab7 !important}.deep-purple.lighten-5{background-color:#ede7f6 !important}.deep-purple-text.text-lighten-5{color:#ede7f6 !important}.deep-purple.lighten-4{background-color:#d1c4e9 !important}.deep-purple-text.text-lighten-4{color:#d1c4e9 !important}.deep-purple.lighten-3{background-color:#b39ddb !important}.deep-purple-text.text-lighten-3{color:#b39ddb !important}.deep-purple.lighten-2{background-color:#9575cd !important}.deep-purple-text.text-lighten-2{color:#9575cd !important}.deep-purple.lighten-1{background-color:#7e57c2 !important}.deep-purple-text.text-lighten-1{color:#7e57c2 !important}.deep-purple.darken-1{background-color:#5e35b1 !important}.deep-purple-text.text-darken-1{color:#5e35b1 !important}.deep-purple.darken-2{background-color:#512da8 !important}.deep-purple-text.text-darken-2{color:#512da8 !important}.deep-purple.darken-3{background-color:#4527a0 !important}.deep-purple-text.text-darken-3{color:#4527a0 !important}.deep-purple.darken-4{background-color:#311b92 !important}.deep-purple-text.text-darken-4{color:#311b92 !important}.deep-purple.accent-1{background-color:#b388ff !important}.deep-purple-text.text-accent-1{color:#b388ff !important}.deep-purple.accent-2{background-color:#7c4dff !important}.deep-purple-text.text-accent-2{color:#7c4dff !important}.deep-purple.accent-3{background-color:#651fff !important}.deep-purple-text.text-accent-3{color:#651fff !important}.deep-purple.accent-4{background-color:#6200ea !important}.deep-purple-text.text-accent-4{color:#6200ea !important}.indigo{background-color:#3f51b5 !important}.indigo-text{color:#3f51b5 !important}.indigo.lighten-5{background-color:#e8eaf6 !important}.indigo-text.text-lighten-5{color:#e8eaf6 !important}.indigo.lighten-4{background-color:#c5cae9 !important}.indigo-text.text-lighten-4{color:#c5cae9 !important}.indigo.lighten-3{background-color:#9fa8da !important}.indigo-text.text-lighten-3{color:#9fa8da !important}.indigo.lighten-2{background-color:#7986cb !important}.indigo-text.text-lighten-2{color:#7986cb !important}.indigo.lighten-1{background-color:#5c6bc0 !important}.indigo-text.text-lighten-1{color:#5c6bc0 !important}.indigo.darken-1{background-color:#3949ab !important}.indigo-text.text-darken-1{color:#3949ab !important}.indigo.darken-2{background-color:#303f9f !important}.indigo-text.text-darken-2{color:#303f9f !important}.indigo.darken-3{background-color:#283593 !important}.indigo-text.text-darken-3{color:#283593 !important}.indigo.darken-4{background-color:#1a237e !important}.indigo-text.text-darken-4{color:#1a237e !important}.indigo.accent-1{background-color:#8c9eff !important}.indigo-text.text-accent-1{color:#8c9eff !important}.indigo.accent-2{background-color:#536dfe !important}.indigo-text.text-accent-2{color:#536dfe !important}.indigo.accent-3{background-color:#3d5afe !important}.indigo-text.text-accent-3{color:#3d5afe !important}.indigo.accent-4{background-color:#304ffe !important}.indigo-text.text-accent-4{color:#304ffe !important}.blue{background-color:#2196F3 !important}.blue-text{color:#2196F3 !important}.blue.lighten-5{background-color:#E3F2FD !important}.blue-text.text-lighten-5{color:#E3F2FD !important}.blue.lighten-4{background-color:#BBDEFB !important}.blue-text.text-lighten-4{color:#BBDEFB !important}.blue.lighten-3{background-color:#90CAF9 !important}.blue-text.text-lighten-3{color:#90CAF9 !important}.blue.lighten-2{background-color:#64B5F6 !important}.blue-text.text-lighten-2{color:#64B5F6 !important}.blue.lighten-1{background-color:#42A5F5 !important}.blue-text.text-lighten-1{color:#42A5F5 !important}.blue.darken-1{background-color:#1E88E5 !important}.blue-text.text-darken-1{color:#1E88E5 !important}.blue.darken-2{background-color:#1976D2 !important}.blue-text.text-darken-2{color:#1976D2 !important}.blue.darken-3{background-color:#1565C0 !important}.blue-text.text-darken-3{color:#1565C0 !important}.blue.darken-4{background-color:#0D47A1 !important}.blue-text.text-darken-4{color:#0D47A1 !important}.blue.accent-1{background-color:#82B1FF !important}.blue-text.text-accent-1{color:#82B1FF !important}.blue.accent-2{background-color:#448AFF !important}.blue-text.text-accent-2{color:#448AFF !important}.blue.accent-3{background-color:#2979FF !important}.blue-text.text-accent-3{color:#2979FF !important}.blue.accent-4{background-color:#2962FF !important}.blue-text.text-accent-4{color:#2962FF !important}.light-blue{background-color:#03a9f4 !important}.light-blue-text{color:#03a9f4 !important}.light-blue.lighten-5{background-color:#e1f5fe !important}.light-blue-text.text-lighten-5{color:#e1f5fe !important}.light-blue.lighten-4{background-color:#b3e5fc !important}.light-blue-text.text-lighten-4{color:#b3e5fc !important}.light-blue.lighten-3{background-color:#81d4fa !important}.light-blue-text.text-lighten-3{color:#81d4fa !important}.light-blue.lighten-2{background-color:#4fc3f7 !important}.light-blue-text.text-lighten-2{color:#4fc3f7 !important}.light-blue.lighten-1{background-color:#29b6f6 !important}.light-blue-text.text-lighten-1{color:#29b6f6 !important}.light-blue.darken-1{background-color:#039be5 !important}.light-blue-text.text-darken-1{color:#039be5 !important}.light-blue.darken-2{background-color:#0288d1 !important}.light-blue-text.text-darken-2{color:#0288d1 !important}.light-blue.darken-3{background-color:#0277bd !important}.light-blue-text.text-darken-3{color:#0277bd !important}.light-blue.darken-4{background-color:#01579b !important}.light-blue-text.text-darken-4{color:#01579b !important}.light-blue.accent-1{background-color:#80d8ff !important}.light-blue-text.text-accent-1{color:#80d8ff !important}.light-blue.accent-2{background-color:#40c4ff !important}.light-blue-text.text-accent-2{color:#40c4ff !important}.light-blue.accent-3{background-color:#00b0ff !important}.light-blue-text.text-accent-3{color:#00b0ff !important}.light-blue.accent-4{background-color:#0091ea !important}.light-blue-text.text-accent-4{color:#0091ea !important}.cyan{background-color:#00bcd4 !important}.cyan-text{color:#00bcd4 !important}.cyan.lighten-5{background-color:#e0f7fa !important}.cyan-text.text-lighten-5{color:#e0f7fa !important}.cyan.lighten-4{background-color:#b2ebf2 !important}.cyan-text.text-lighten-4{color:#b2ebf2 !important}.cyan.lighten-3{background-color:#80deea !important}.cyan-text.text-lighten-3{color:#80deea !important}.cyan.lighten-2{background-color:#4dd0e1 !important}.cyan-text.text-lighten-2{color:#4dd0e1 !important}.cyan.lighten-1{background-color:#26c6da !important}.cyan-text.text-lighten-1{color:#26c6da !important}.cyan.darken-1{background-color:#00acc1 !important}.cyan-text.text-darken-1{color:#00acc1 !important}.cyan.darken-2{background-color:#0097a7 !important}.cyan-text.text-darken-2{color:#0097a7 !important}.cyan.darken-3{background-color:#00838f !important}.cyan-text.text-darken-3{color:#00838f !important}.cyan.darken-4{background-color:#006064 !important}.cyan-text.text-darken-4{color:#006064 !important}.cyan.accent-1{background-color:#84ffff !important}.cyan-text.text-accent-1{color:#84ffff !important}.cyan.accent-2{background-color:#18ffff !important}.cyan-text.text-accent-2{color:#18ffff !important}.cyan.accent-3{background-color:#00e5ff !important}.cyan-text.text-accent-3{color:#00e5ff !important}.cyan.accent-4{background-color:#00b8d4 !important}.cyan-text.text-accent-4{color:#00b8d4 !important}.teal{background-color:#009688 !important}.teal-text{color:#009688 !important}.teal.lighten-5{background-color:#e0f2f1 !important}.teal-text.text-lighten-5{color:#e0f2f1 !important}.teal.lighten-4{background-color:#b2dfdb !important}.teal-text.text-lighten-4{color:#b2dfdb !important}.teal.lighten-3{background-color:#80cbc4 !important}.teal-text.text-lighten-3{color:#80cbc4 !important}.teal.lighten-2{background-color:#4db6ac !important}.teal-text.text-lighten-2{color:#4db6ac !important}.teal.lighten-1{background-color:#26a69a !important}.teal-text.text-lighten-1{color:#26a69a !important}.teal.darken-1{background-color:#00897b !important}.teal-text.text-darken-1{color:#00897b !important}.teal.darken-2{background-color:#00796b !important}.teal-text.text-darken-2{color:#00796b !important}.teal.darken-3{background-color:#00695c !important}.teal-text.text-darken-3{color:#00695c !important}.teal.darken-4{background-color:#004d40 !important}.teal-text.text-darken-4{color:#004d40 !important}.teal.accent-1{background-color:#a7ffeb !important}.teal-text.text-accent-1{color:#a7ffeb !important}.teal.accent-2{background-color:#64ffda !important}.teal-text.text-accent-2{color:#64ffda !important}.teal.accent-3{background-color:#1de9b6 !important}.teal-text.text-accent-3{color:#1de9b6 !important}.teal.accent-4{background-color:#00bfa5 !important}.teal-text.text-accent-4{color:#00bfa5 !important}.green{background-color:#4CAF50 !important}.green-text{color:#4CAF50 !important}.green.lighten-5{background-color:#E8F5E9 !important}.green-text.text-lighten-5{color:#E8F5E9 !important}.green.lighten-4{background-color:#C8E6C9 !important}.green-text.text-lighten-4{color:#C8E6C9 !important}.green.lighten-3{background-color:#A5D6A7 !important}.green-text.text-lighten-3{color:#A5D6A7 !important}.green.lighten-2{background-color:#81C784 !important}.green-text.text-lighten-2{color:#81C784 !important}.green.lighten-1{background-color:#66BB6A !important}.green-text.text-lighten-1{color:#66BB6A !important}.green.darken-1{background-color:#43A047 !important}.green-text.text-darken-1{color:#43A047 !important}.green.darken-2{background-color:#388E3C !important}.green-text.text-darken-2{color:#388E3C !important}.green.darken-3{background-color:#2E7D32 !important}.green-text.text-darken-3{color:#2E7D32 !important}.green.darken-4{background-color:#1B5E20 !important}.green-text.text-darken-4{color:#1B5E20 !important}.green.accent-1{background-color:#B9F6CA !important}.green-text.text-accent-1{color:#B9F6CA !important}.green.accent-2{background-color:#69F0AE !important}.green-text.text-accent-2{color:#69F0AE !important}.green.accent-3{background-color:#00E676 !important}.green-text.text-accent-3{color:#00E676 !important}.green.accent-4{background-color:#00C853 !important}.green-text.text-accent-4{color:#00C853 !important}.light-green{background-color:#8bc34a !important}.light-green-text{color:#8bc34a !important}.light-green.lighten-5{background-color:#f1f8e9 !important}.light-green-text.text-lighten-5{color:#f1f8e9 !important}.light-green.lighten-4{background-color:#dcedc8 !important}.light-green-text.text-lighten-4{color:#dcedc8 !important}.light-green.lighten-3{background-color:#c5e1a5 !important}.light-green-text.text-lighten-3{color:#c5e1a5 !important}.light-green.lighten-2{background-color:#aed581 !important}.light-green-text.text-lighten-2{color:#aed581 !important}.light-green.lighten-1{background-color:#9ccc65 !important}.light-green-text.text-lighten-1{color:#9ccc65 !important}.light-green.darken-1{background-color:#7cb342 !important}.light-green-text.text-darken-1{color:#7cb342 !important}.light-green.darken-2{background-color:#689f38 !important}.light-green-text.text-darken-2{color:#689f38 !important}.light-green.darken-3{background-color:#558b2f !important}.light-green-text.text-darken-3{color:#558b2f !important}.light-green.darken-4{background-color:#33691e !important}.light-green-text.text-darken-4{color:#33691e !important}.light-green.accent-1{background-color:#ccff90 !important}.light-green-text.text-accent-1{color:#ccff90 !important}.light-green.accent-2{background-color:#b2ff59 !important}.light-green-text.text-accent-2{color:#b2ff59 !important}.light-green.accent-3{background-color:#76ff03 !important}.light-green-text.text-accent-3{color:#76ff03 !important}.light-green.accent-4{background-color:#64dd17 !important}.light-green-text.text-accent-4{color:#64dd17 !important}.lime{background-color:#cddc39 !important}.lime-text{color:#cddc39 !important}.lime.lighten-5{background-color:#f9fbe7 !important}.lime-text.text-lighten-5{color:#f9fbe7 !important}.lime.lighten-4{background-color:#f0f4c3 !important}.lime-text.text-lighten-4{color:#f0f4c3 !important}.lime.lighten-3{background-color:#e6ee9c !important}.lime-text.text-lighten-3{color:#e6ee9c !important}.lime.lighten-2{background-color:#dce775 !important}.lime-text.text-lighten-2{color:#dce775 !important}.lime.lighten-1{background-color:#d4e157 !important}.lime-text.text-lighten-1{color:#d4e157 !important}.lime.darken-1{background-color:#c0ca33 !important}.lime-text.text-darken-1{color:#c0ca33 !important}.lime.darken-2{background-color:#afb42b !important}.lime-text.text-darken-2{color:#afb42b !important}.lime.darken-3{background-color:#9e9d24 !important}.lime-text.text-darken-3{color:#9e9d24 !important}.lime.darken-4{background-color:#827717 !important}.lime-text.text-darken-4{color:#827717 !important}.lime.accent-1{background-color:#f4ff81 !important}.lime-text.text-accent-1{color:#f4ff81 !important}.lime.accent-2{background-color:#eeff41 !important}.lime-text.text-accent-2{color:#eeff41 !important}.lime.accent-3{background-color:#c6ff00 !important}.lime-text.text-accent-3{color:#c6ff00 !important}.lime.accent-4{background-color:#aeea00 !important}.lime-text.text-accent-4{color:#aeea00 !important}.yellow{background-color:#ffeb3b !important}.yellow-text{color:#ffeb3b !important}.yellow.lighten-5{background-color:#fffde7 !important}.yellow-text.text-lighten-5{color:#fffde7 !important}.yellow.lighten-4{background-color:#fff9c4 !important}.yellow-text.text-lighten-4{color:#fff9c4 !important}.yellow.lighten-3{background-color:#fff59d !important}.yellow-text.text-lighten-3{color:#fff59d !important}.yellow.lighten-2{background-color:#fff176 !important}.yellow-text.text-lighten-2{color:#fff176 !important}.yellow.lighten-1{background-color:#ffee58 !important}.yellow-text.text-lighten-1{color:#ffee58 !important}.yellow.darken-1{background-color:#fdd835 !important}.yellow-text.text-darken-1{color:#fdd835 !important}.yellow.darken-2{background-color:#fbc02d !important}.yellow-text.text-darken-2{color:#fbc02d !important}.yellow.darken-3{background-color:#f9a825 !important}.yellow-text.text-darken-3{color:#f9a825 !important}.yellow.darken-4{background-color:#f57f17 !important}.yellow-text.text-darken-4{color:#f57f17 !important}.yellow.accent-1{background-color:#ffff8d !important}.yellow-text.text-accent-1{color:#ffff8d !important}.yellow.accent-2{background-color:#ff0 !important}.yellow-text.text-accent-2{color:#ff0 !important}.yellow.accent-3{background-color:#ffea00 !important}.yellow-text.text-accent-3{color:#ffea00 !important}.yellow.accent-4{background-color:#ffd600 !important}.yellow-text.text-accent-4{color:#ffd600 !important}.amber{background-color:#ffc107 !important}.amber-text{color:#ffc107 !important}.amber.lighten-5{background-color:#fff8e1 !important}.amber-text.text-lighten-5{color:#fff8e1 !important}.amber.lighten-4{background-color:#ffecb3 !important}.amber-text.text-lighten-4{color:#ffecb3 !important}.amber.lighten-3{background-color:#ffe082 !important}.amber-text.text-lighten-3{color:#ffe082 !important}.amber.lighten-2{background-color:#ffd54f !important}.amber-text.text-lighten-2{color:#ffd54f !important}.amber.lighten-1{background-color:#ffca28 !important}.amber-text.text-lighten-1{color:#ffca28 !important}.amber.darken-1{background-color:#ffb300 !important}.amber-text.text-darken-1{color:#ffb300 !important}.amber.darken-2{background-color:#ffa000 !important}.amber-text.text-darken-2{color:#ffa000 !important}.amber.darken-3{background-color:#ff8f00 !important}.amber-text.text-darken-3{color:#ff8f00 !important}.amber.darken-4{background-color:#ff6f00 !important}.amber-text.text-darken-4{color:#ff6f00 !important}.amber.accent-1{background-color:#ffe57f !important}.amber-text.text-accent-1{color:#ffe57f !important}.amber.accent-2{background-color:#ffd740 !important}.amber-text.text-accent-2{color:#ffd740 !important}.amber.accent-3{background-color:#ffc400 !important}.amber-text.text-accent-3{color:#ffc400 !important}.amber.accent-4{background-color:#ffab00 !important}.amber-text.text-accent-4{color:#ffab00 !important}.orange{background-color:#ff9800 !important}.orange-text{color:#ff9800 !important}.orange.lighten-5{background-color:#fff3e0 !important}.orange-text.text-lighten-5{color:#fff3e0 !important}.orange.lighten-4{background-color:#ffe0b2 !important}.orange-text.text-lighten-4{color:#ffe0b2 !important}.orange.lighten-3{background-color:#ffcc80 !important}.orange-text.text-lighten-3{color:#ffcc80 !important}.orange.lighten-2{background-color:#ffb74d !important}.orange-text.text-lighten-2{color:#ffb74d !important}.orange.lighten-1{background-color:#ffa726 !important}.orange-text.text-lighten-1{color:#ffa726 !important}.orange.darken-1{background-color:#fb8c00 !important}.orange-text.text-darken-1{color:#fb8c00 !important}.orange.darken-2{background-color:#f57c00 !important}.orange-text.text-darken-2{color:#f57c00 !important}.orange.darken-3{background-color:#ef6c00 !important}.orange-text.text-darken-3{color:#ef6c00 !important}.orange.darken-4{background-color:#e65100 !important}.orange-text.text-darken-4{color:#e65100 !important}.orange.accent-1{background-color:#ffd180 !important}.orange-text.text-accent-1{color:#ffd180 !important}.orange.accent-2{background-color:#ffab40 !important}.orange-text.text-accent-2{color:#ffab40 !important}.orange.accent-3{background-color:#ff9100 !important}.orange-text.text-accent-3{color:#ff9100 !important}.orange.accent-4{background-color:#ff6d00 !important}.orange-text.text-accent-4{color:#ff6d00 !important}.deep-orange{background-color:#ff5722 !important}.deep-orange-text{color:#ff5722 !important}.deep-orange.lighten-5{background-color:#fbe9e7 !important}.deep-orange-text.text-lighten-5{color:#fbe9e7 !important}.deep-orange.lighten-4{background-color:#ffccbc !important}.deep-orange-text.text-lighten-4{color:#ffccbc !important}.deep-orange.lighten-3{background-color:#ffab91 !important}.deep-orange-text.text-lighten-3{color:#ffab91 !important}.deep-orange.lighten-2{background-color:#ff8a65 !important}.deep-orange-text.text-lighten-2{color:#ff8a65 !important}.deep-orange.lighten-1{background-color:#ff7043 !important}.deep-orange-text.text-lighten-1{color:#ff7043 !important}.deep-orange.darken-1{background-color:#f4511e !important}.deep-orange-text.text-darken-1{color:#f4511e !important}.deep-orange.darken-2{background-color:#e64a19 !important}.deep-orange-text.text-darken-2{color:#e64a19 !important}.deep-orange.darken-3{background-color:#d84315 !important}.deep-orange-text.text-darken-3{color:#d84315 !important}.deep-orange.darken-4{background-color:#bf360c !important}.deep-orange-text.text-darken-4{color:#bf360c !important}.deep-orange.accent-1{background-color:#ff9e80 !important}.deep-orange-text.text-accent-1{color:#ff9e80 !important}.deep-orange.accent-2{background-color:#ff6e40 !important}.deep-orange-text.text-accent-2{color:#ff6e40 !important}.deep-orange.accent-3{background-color:#ff3d00 !important}.deep-orange-text.text-accent-3{color:#ff3d00 !important}.deep-orange.accent-4{background-color:#dd2c00 !important}.deep-orange-text.text-accent-4{color:#dd2c00 !important}.brown{background-color:#795548 !important}.brown-text{color:#795548 !important}.brown.lighten-5{background-color:#efebe9 !important}.brown-text.text-lighten-5{color:#efebe9 !important}.brown.lighten-4{background-color:#d7ccc8 !important}.brown-text.text-lighten-4{color:#d7ccc8 !important}.brown.lighten-3{background-color:#bcaaa4 !important}.brown-text.text-lighten-3{color:#bcaaa4 !important}.brown.lighten-2{background-color:#a1887f !important}.brown-text.text-lighten-2{color:#a1887f !important}.brown.lighten-1{background-color:#8d6e63 !important}.brown-text.text-lighten-1{color:#8d6e63 !important}.brown.darken-1{background-color:#6d4c41 !important}.brown-text.text-darken-1{color:#6d4c41 !important}.brown.darken-2{background-color:#5d4037 !important}.brown-text.text-darken-2{color:#5d4037 !important}.brown.darken-3{background-color:#4e342e !important}.brown-text.text-darken-3{color:#4e342e !important}.brown.darken-4{background-color:#3e2723 !important}.brown-text.text-darken-4{color:#3e2723 !important}.blue-grey{background-color:#607d8b !important}.blue-grey-text{color:#607d8b !important}.blue-grey.lighten-5{background-color:#eceff1 !important}.blue-grey-text.text-lighten-5{color:#eceff1 !important}.blue-grey.lighten-4{background-color:#cfd8dc !important}.blue-grey-text.text-lighten-4{color:#cfd8dc !important}.blue-grey.lighten-3{background-color:#b0bec5 !important}.blue-grey-text.text-lighten-3{color:#b0bec5 !important}.blue-grey.lighten-2{background-color:#90a4ae !important}.blue-grey-text.text-lighten-2{color:#90a4ae !important}.blue-grey.lighten-1{background-color:#78909c !important}.blue-grey-text.text-lighten-1{color:#78909c !important}.blue-grey.darken-1{background-color:#546e7a !important}.blue-grey-text.text-darken-1{color:#546e7a !important}.blue-grey.darken-2{background-color:#455a64 !important}.blue-grey-text.text-darken-2{color:#455a64 !important}.blue-grey.darken-3{background-color:#37474f !important}.blue-grey-text.text-darken-3{color:#37474f !important}.blue-grey.darken-4{background-color:#263238 !important}.blue-grey-text.text-darken-4{color:#263238 !important}.grey{background-color:#9e9e9e !important}.grey-text{color:#9e9e9e !important}.grey.lighten-5{background-color:#fafafa !important}.grey-text.text-lighten-5{color:#fafafa !important}.grey.lighten-4{background-color:#f5f5f5 !important}.grey-text.text-lighten-4{color:#f5f5f5 !important}.grey.lighten-3{background-color:#eee !important}.grey-text.text-lighten-3{color:#eee !important}.grey.lighten-2{background-color:#e0e0e0 !important}.grey-text.text-lighten-2{color:#e0e0e0 !important}.grey.lighten-1{background-color:#bdbdbd !important}.grey-text.text-lighten-1{color:#bdbdbd !important}.grey.darken-1{background-color:#757575 !important}.grey-text.text-darken-1{color:#757575 !important}.grey.darken-2{background-color:#616161 !important}.grey-text.text-darken-2{color:#616161 !important}.grey.darken-3{background-color:#424242 !important}.grey-text.text-darken-3{color:#424242 !important}.grey.darken-4{background-color:#212121 !important}.grey-text.text-darken-4{color:#212121 !important}.black{background-color:#000 !important}.black-text{color:#000 !important}.white{background-color:#fff !important}.white-text{color:#fff !important}.transparent{background-color:transparent !important}.transparent-text{color:transparent !important}/*! 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{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"]{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;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}html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}ul:not(.browser-default){padding-left:0;list-style-type:none}ul:not(.browser-default) li{list-style-type:none}a{color:#039be5;text-decoration:none;-webkit-tap-highlight-color:transparent}.valign-wrapper{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.valign-wrapper .valign{display:block}.clearfix{clear:both}.z-depth-0{box-shadow:none !important}.z-depth-1,nav,.card-panel,.card,.toast,.btn,.btn-large,.btn-floating,.dropdown-content,.collapsible,.side-nav{box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 1px 5px 0 rgba(0,0,0,0.12),0 3px 1px -2px rgba(0,0,0,0.2)}.z-depth-1-half,.btn:hover,.btn-large:hover,.btn-floating:hover{box-shadow:0 3px 3px 0 rgba(0,0,0,0.14),0 1px 7px 0 rgba(0,0,0,0.12),0 3px 1px -1px rgba(0,0,0,0.2)}.z-depth-2{box-shadow:0 4px 5px 0 rgba(0,0,0,0.14),0 1px 10px 0 rgba(0,0,0,0.12),0 2px 4px -1px rgba(0,0,0,0.3)}.z-depth-3{box-shadow:0 6px 10px 0 rgba(0,0,0,0.14),0 1px 18px 0 rgba(0,0,0,0.12),0 3px 5px -1px rgba(0,0,0,0.3)}.z-depth-4,.modal{box-shadow:0 8px 10px 1px rgba(0,0,0,0.14),0 3px 14px 2px rgba(0,0,0,0.12),0 5px 5px -3px rgba(0,0,0,0.3)}.z-depth-5{box-shadow:0 16px 24px 2px rgba(0,0,0,0.14),0 6px 30px 5px rgba(0,0,0,0.12),0 8px 10px -5px rgba(0,0,0,0.3)}.hoverable{transition:box-shadow .25s;box-shadow:0}.hoverable:hover{transition:box-shadow .25s;box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}.divider{height:1px;overflow:hidden;background-color:#e0e0e0}blockquote{margin:20px 0;padding-left:1.5rem;border-left:5px solid #ee6e73}i{line-height:inherit}i.left{float:left;margin-right:15px}i.right{float:right;margin-left:15px}i.tiny{font-size:1rem}i.small{font-size:2rem}i.medium{font-size:4rem}i.large{font-size:6rem}img.responsive-img,video.responsive-video{max-width:100%;height:auto}.pagination li{display:inline-block;border-radius:2px;text-align:center;vertical-align:top;height:30px}.pagination li a{color:#444;display:inline-block;font-size:1.2rem;padding:0 10px;line-height:30px}.pagination li.active a{color:#fff}.pagination li.active{background-color:#ee6e73}.pagination li.disabled a{cursor:default;color:#999}.pagination li i{font-size:2rem}.pagination li.pages ul li{display:inline-block;float:none}@media only screen and (max-width: 992px){.pagination{width:100%}.pagination li.prev,.pagination li.next{width:10%}.pagination li.pages{width:80%;overflow:hidden;white-space:nowrap}}.breadcrumb{font-size:18px;color:rgba(255,255,255,0.7)}.breadcrumb i,.breadcrumb [class^="mdi-"],.breadcrumb [class*="mdi-"],.breadcrumb i.material-icons{display:inline-block;float:left;font-size:24px}.breadcrumb:before{content:'\E5CC';color:rgba(255,255,255,0.7);vertical-align:top;display:inline-block;font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:25px;margin:0 10px 0 8px;-webkit-font-smoothing:antialiased}.breadcrumb:first-child:before{display:none}.breadcrumb:last-child{color:#fff}.parallax-container{position:relative;overflow:hidden;height:500px}.parallax{position:absolute;top:0;left:0;right:0;bottom:0;z-index:-1}.parallax img{display:none;position:absolute;left:50%;bottom:0;min-width:100%;min-height:100%;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);-webkit-transform:translateX(-50%);transform:translateX(-50%)}.pin-top,.pin-bottom{position:relative}.pinned{position:fixed !important}ul.staggered-list li{opacity:0}.fade-in{opacity:0;-webkit-transform-origin:0 50%;transform-origin:0 50%}@media only screen and (max-width: 600px){.hide-on-small-only,.hide-on-small-and-down{display:none !important}}@media only screen and (max-width: 992px){.hide-on-med-and-down{display:none !important}}@media only screen and (min-width: 601px){.hide-on-med-and-up{display:none !important}}@media only screen and (min-width: 600px) and (max-width: 992px){.hide-on-med-only{display:none !important}}@media only screen and (min-width: 993px){.hide-on-large-only{display:none !important}}@media only screen and (min-width: 993px){.show-on-large{display:block !important}}@media only screen and (min-width: 600px) and (max-width: 992px){.show-on-medium{display:block !important}}@media only screen and (max-width: 600px){.show-on-small{display:block !important}}@media only screen and (min-width: 601px){.show-on-medium-and-up{display:block !important}}@media only screen and (max-width: 992px){.show-on-medium-and-down{display:block !important}}@media only screen and (max-width: 600px){.center-on-small-only{text-align:center}}footer.page-footer{padding-top:20px;background-color:#ee6e73}footer.page-footer .footer-copyright{overflow:hidden;min-height:50px;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;padding:10px 0px;color:rgba(255,255,255,0.8);background-color:rgba(51,51,51,0.08)}table,th,td{border:none}table{width:100%;display:table}table.bordered>thead>tr,table.bordered>tbody>tr{border-bottom:1px solid #d0d0d0}table.striped>tbody>tr:nth-child(odd){background-color:#f2f2f2}table.striped>tbody>tr>td{border-radius:0}table.highlight>tbody>tr{transition:background-color .25s ease}table.highlight>tbody>tr:hover{background-color:#f2f2f2}table.centered thead tr th,table.centered tbody tr td{text-align:center}thead{border-bottom:1px solid #d0d0d0}td,th{padding:15px 5px;display:table-cell;text-align:left;vertical-align:middle;border-radius:2px}@media only screen and (max-width: 992px){table.responsive-table{width:100%;border-collapse:collapse;border-spacing:0;display:block;position:relative}table.responsive-table td:empty:before{content:'\00a0'}table.responsive-table th,table.responsive-table td{margin:0;vertical-align:top}table.responsive-table th{text-align:left}table.responsive-table thead{display:block;float:left}table.responsive-table thead tr{display:block;padding:0 10px 0 0}table.responsive-table thead tr th::before{content:"\00a0"}table.responsive-table tbody{display:block;width:auto;position:relative;overflow-x:auto;white-space:nowrap}table.responsive-table tbody tr{display:inline-block;vertical-align:top}table.responsive-table th{display:block;text-align:right}table.responsive-table td{display:block;min-height:1.25em;text-align:left}table.responsive-table tr{padding:0 10px}table.responsive-table thead{border:0;border-right:1px solid #d0d0d0}table.responsive-table.bordered th{border-bottom:0;border-left:0}table.responsive-table.bordered td{border-left:0;border-right:0;border-bottom:0}table.responsive-table.bordered tr{border:0}table.responsive-table.bordered tbody tr{border-right:1px solid #d0d0d0}}.collection{margin:.5rem 0 1rem 0;border:1px solid #e0e0e0;border-radius:2px;overflow:hidden;position:relative}.collection .collection-item{background-color:#fff;line-height:1.5rem;padding:10px 20px;margin:0;border-bottom:1px solid #e0e0e0}.collection .collection-item.avatar{min-height:84px;padding-left:72px;position:relative}.collection .collection-item.avatar .circle{position:absolute;width:42px;height:42px;overflow:hidden;left:15px;display:inline-block;vertical-align:middle}.collection .collection-item.avatar i.circle{font-size:18px;line-height:42px;color:#fff;background-color:#999;text-align:center}.collection .collection-item.avatar .title{font-size:16px}.collection .collection-item.avatar p{margin:0}.collection .collection-item.avatar .secondary-content{position:absolute;top:16px;right:16px}.collection .collection-item:last-child{border-bottom:none}.collection .collection-item.active{background-color:#26a69a;color:#eafaf9}.collection .collection-item.active .secondary-content{color:#fff}.collection a.collection-item{display:block;transition:.25s;color:#26a69a}.collection a.collection-item:not(.active):hover{background-color:#ddd}.collection.with-header .collection-header{background-color:#fff;border-bottom:1px solid #e0e0e0;padding:10px 20px}.collection.with-header .collection-item{padding-left:30px}.collection.with-header .collection-item.avatar{padding-left:72px}.secondary-content{float:right;color:#26a69a}.collapsible .collection{margin:0;border:none}.video-container{position:relative;padding-bottom:56.25%;height:0;overflow:hidden}.video-container iframe,.video-container object,.video-container embed{position:absolute;top:0;left:0;width:100%;height:100%}.progress{position:relative;height:4px;display:block;width:100%;background-color:#acece6;border-radius:2px;margin:.5rem 0 1rem 0;overflow:hidden}.progress .determinate{position:absolute;top:0;left:0;bottom:0;background-color:#26a69a;transition:width .3s linear}.progress .indeterminate{background-color:#26a69a}.progress .indeterminate:before{content:'';position:absolute;background-color:inherit;top:0;left:0;bottom:0;will-change:left, right;-webkit-animation:indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;animation:indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite}.progress .indeterminate:after{content:'';position:absolute;background-color:inherit;top:0;left:0;bottom:0;will-change:left, right;-webkit-animation:indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;animation:indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;-webkit-animation-delay:1.15s;animation-delay:1.15s}@-webkit-keyframes indeterminate{0%{left:-35%;right:100%}60%{left:100%;right:-90%}100%{left:100%;right:-90%}}@keyframes indeterminate{0%{left:-35%;right:100%}60%{left:100%;right:-90%}100%{left:100%;right:-90%}}@-webkit-keyframes indeterminate-short{0%{left:-200%;right:100%}60%{left:107%;right:-8%}100%{left:107%;right:-8%}}@keyframes indeterminate-short{0%{left:-200%;right:100%}60%{left:107%;right:-8%}100%{left:107%;right:-8%}}.hide{display:none !important}.left-align{text-align:left}.right-align{text-align:right}.center,.center-align{text-align:center}.left{float:left !important}.right{float:right !important}.no-select,input[type=range],input[type=range]+.thumb{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.circle{border-radius:50%}.center-block{display:block;margin-left:auto;margin-right:auto}.truncate{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.no-padding{padding:0 !important}span.badge{min-width:3rem;padding:0 6px;margin-left:14px;text-align:center;font-size:1rem;line-height:22px;height:22px;color:#757575;float:right;box-sizing:border-box}span.badge.new{font-weight:300;font-size:0.8rem;color:#fff;background-color:#26a69a;border-radius:2px}span.badge.new:after{content:" new"}span.badge[data-badge-caption]::after{content:" " attr(data-badge-caption)}nav ul a span.badge{display:inline-block;float:none;margin-left:4px;line-height:22px;height:22px}.collection-item span.badge{margin-top:calc(.75rem - 11px)}.collapsible span.badge{margin-top:calc(1.5rem - 11px)}.side-nav span.badge{margin-top:calc(24px - 11px)}.material-icons{text-rendering:optimizeLegibility;-webkit-font-feature-settings:'liga';-moz-font-feature-settings:'liga';font-feature-settings:'liga'}.container{margin:0 auto;max-width:1280px;width:90%}@media only screen and (min-width: 601px){.container{width:85%}}@media only screen and (min-width: 993px){.container{width:70%}}.container .row{margin-left:-.75rem;margin-right:-.75rem}.section{padding-top:1rem;padding-bottom:1rem}.section.no-pad{padding:0}.section.no-pad-bot{padding-bottom:0}.section.no-pad-top{padding-top:0}.row{margin-left:auto;margin-right:auto;margin-bottom:20px}.row:after{content:"";display:table;clear:both}.row .col{float:left;box-sizing:border-box;padding:0 .75rem;min-height:1px}.row .col[class*="push-"],.row .col[class*="pull-"]{position:relative}.row .col.s1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.s4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.s7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.s10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-s1{margin-left:8.3333333333%}.row .col.pull-s1{right:8.3333333333%}.row .col.push-s1{left:8.3333333333%}.row .col.offset-s2{margin-left:16.6666666667%}.row .col.pull-s2{right:16.6666666667%}.row .col.push-s2{left:16.6666666667%}.row .col.offset-s3{margin-left:25%}.row .col.pull-s3{right:25%}.row .col.push-s3{left:25%}.row .col.offset-s4{margin-left:33.3333333333%}.row .col.pull-s4{right:33.3333333333%}.row .col.push-s4{left:33.3333333333%}.row .col.offset-s5{margin-left:41.6666666667%}.row .col.pull-s5{right:41.6666666667%}.row .col.push-s5{left:41.6666666667%}.row .col.offset-s6{margin-left:50%}.row .col.pull-s6{right:50%}.row .col.push-s6{left:50%}.row .col.offset-s7{margin-left:58.3333333333%}.row .col.pull-s7{right:58.3333333333%}.row .col.push-s7{left:58.3333333333%}.row .col.offset-s8{margin-left:66.6666666667%}.row .col.pull-s8{right:66.6666666667%}.row .col.push-s8{left:66.6666666667%}.row .col.offset-s9{margin-left:75%}.row .col.pull-s9{right:75%}.row .col.push-s9{left:75%}.row .col.offset-s10{margin-left:83.3333333333%}.row .col.pull-s10{right:83.3333333333%}.row .col.push-s10{left:83.3333333333%}.row .col.offset-s11{margin-left:91.6666666667%}.row .col.pull-s11{right:91.6666666667%}.row .col.push-s11{left:91.6666666667%}.row .col.offset-s12{margin-left:100%}.row .col.pull-s12{right:100%}.row .col.push-s12{left:100%}@media only screen and (min-width: 601px){.row .col.m1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.m4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.m7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.m10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-m1{margin-left:8.3333333333%}.row .col.pull-m1{right:8.3333333333%}.row .col.push-m1{left:8.3333333333%}.row .col.offset-m2{margin-left:16.6666666667%}.row .col.pull-m2{right:16.6666666667%}.row .col.push-m2{left:16.6666666667%}.row .col.offset-m3{margin-left:25%}.row .col.pull-m3{right:25%}.row .col.push-m3{left:25%}.row .col.offset-m4{margin-left:33.3333333333%}.row .col.pull-m4{right:33.3333333333%}.row .col.push-m4{left:33.3333333333%}.row .col.offset-m5{margin-left:41.6666666667%}.row .col.pull-m5{right:41.6666666667%}.row .col.push-m5{left:41.6666666667%}.row .col.offset-m6{margin-left:50%}.row .col.pull-m6{right:50%}.row .col.push-m6{left:50%}.row .col.offset-m7{margin-left:58.3333333333%}.row .col.pull-m7{right:58.3333333333%}.row .col.push-m7{left:58.3333333333%}.row .col.offset-m8{margin-left:66.6666666667%}.row .col.pull-m8{right:66.6666666667%}.row .col.push-m8{left:66.6666666667%}.row .col.offset-m9{margin-left:75%}.row .col.pull-m9{right:75%}.row .col.push-m9{left:75%}.row .col.offset-m10{margin-left:83.3333333333%}.row .col.pull-m10{right:83.3333333333%}.row .col.push-m10{left:83.3333333333%}.row .col.offset-m11{margin-left:91.6666666667%}.row .col.pull-m11{right:91.6666666667%}.row .col.push-m11{left:91.6666666667%}.row .col.offset-m12{margin-left:100%}.row .col.pull-m12{right:100%}.row .col.push-m12{left:100%}}@media only screen and (min-width: 993px){.row .col.l1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.l4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.l7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.l10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-l1{margin-left:8.3333333333%}.row .col.pull-l1{right:8.3333333333%}.row .col.push-l1{left:8.3333333333%}.row .col.offset-l2{margin-left:16.6666666667%}.row .col.pull-l2{right:16.6666666667%}.row .col.push-l2{left:16.6666666667%}.row .col.offset-l3{margin-left:25%}.row .col.pull-l3{right:25%}.row .col.push-l3{left:25%}.row .col.offset-l4{margin-left:33.3333333333%}.row .col.pull-l4{right:33.3333333333%}.row .col.push-l4{left:33.3333333333%}.row .col.offset-l5{margin-left:41.6666666667%}.row .col.pull-l5{right:41.6666666667%}.row .col.push-l5{left:41.6666666667%}.row .col.offset-l6{margin-left:50%}.row .col.pull-l6{right:50%}.row .col.push-l6{left:50%}.row .col.offset-l7{margin-left:58.3333333333%}.row .col.pull-l7{right:58.3333333333%}.row .col.push-l7{left:58.3333333333%}.row .col.offset-l8{margin-left:66.6666666667%}.row .col.pull-l8{right:66.6666666667%}.row .col.push-l8{left:66.6666666667%}.row .col.offset-l9{margin-left:75%}.row .col.pull-l9{right:75%}.row .col.push-l9{left:75%}.row .col.offset-l10{margin-left:83.3333333333%}.row .col.pull-l10{right:83.3333333333%}.row .col.push-l10{left:83.3333333333%}.row .col.offset-l11{margin-left:91.6666666667%}.row .col.pull-l11{right:91.6666666667%}.row .col.push-l11{left:91.6666666667%}.row .col.offset-l12{margin-left:100%}.row .col.pull-l12{right:100%}.row .col.push-l12{left:100%}}nav{color:#fff;background-color:#ee6e73;width:100%;height:56px;line-height:56px}nav.nav-extended{height:auto}nav.nav-extended .nav-wrapper{min-height:56px;height:auto}nav.nav-extended .nav-content{position:relative;line-height:normal}nav a{color:#fff}nav i,nav [class^="mdi-"],nav [class*="mdi-"],nav i.material-icons{display:block;font-size:24px;height:56px;line-height:56px}nav .nav-wrapper{position:relative;height:100%}@media only screen and (min-width: 993px){nav a.button-collapse{display:none}}nav .button-collapse{float:left;position:relative;z-index:1;height:56px;margin:0 18px}nav .button-collapse i{height:56px;line-height:56px}nav .brand-logo{position:absolute;color:#fff;display:inline-block;font-size:2.1rem;padding:0;white-space:nowrap}nav .brand-logo.center{left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}@media only screen and (max-width: 992px){nav .brand-logo{left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}nav .brand-logo.left,nav .brand-logo.right{padding:0;-webkit-transform:none;transform:none}nav .brand-logo.left{left:0.5rem}nav .brand-logo.right{right:0.5rem;left:auto}}nav .brand-logo.right{right:0.5rem;padding:0}nav .brand-logo i,nav .brand-logo [class^="mdi-"],nav .brand-logo [class*="mdi-"],nav .brand-logo i.material-icons{float:left;margin-right:15px}nav .nav-title{display:inline-block;font-size:32px;padding:28px 0}nav ul{margin:0}nav ul li{transition:background-color .3s;float:left;padding:0}nav ul li.active{background-color:rgba(0,0,0,0.1)}nav ul a{transition:background-color .3s;font-size:1rem;color:#fff;display:block;padding:0 15px;cursor:pointer}nav ul a.btn,nav ul a.btn-large,nav ul a.btn-large,nav ul a.btn-flat,nav ul a.btn-floating{margin-top:-2px;margin-left:15px;margin-right:15px}nav ul a.btn>.material-icons,nav ul a.btn-large>.material-icons,nav ul a.btn-large>.material-icons,nav ul a.btn-flat>.material-icons,nav ul a.btn-floating>.material-icons{height:inherit;line-height:inherit}nav ul a:hover{background-color:rgba(0,0,0,0.1)}nav ul.left{float:left}nav form{height:100%}nav .input-field{margin:0;height:100%}nav .input-field input{height:100%;font-size:1.2rem;border:none;padding-left:2rem}nav .input-field input:focus,nav .input-field input[type=text]:valid,nav .input-field input[type=password]:valid,nav .input-field input[type=email]:valid,nav .input-field input[type=url]:valid,nav .input-field input[type=date]:valid{border:none;box-shadow:none}nav .input-field label{top:0;left:0}nav .input-field label i{color:rgba(255,255,255,0.7);transition:color .3s}nav .input-field label.active i{color:#fff}.navbar-fixed{position:relative;height:56px;z-index:997}.navbar-fixed nav{position:fixed}@media only screen and (min-width: 601px){nav.nav-extended .nav-wrapper{min-height:64px}nav,nav .nav-wrapper i,nav a.button-collapse,nav a.button-collapse i{height:64px;line-height:64px}.navbar-fixed{height:64px}}@font-face{font-family:"Roboto";src:local(Roboto Thin),url("../fonts/roboto/Roboto-Thin.eot");src:url("../fonts/roboto/Roboto-Thin.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Thin.woff2") format("woff2"),url("../fonts/roboto/Roboto-Thin.woff") format("woff"),url("../fonts/roboto/Roboto-Thin.ttf") format("truetype");font-weight:200}@font-face{font-family:"Roboto";src:local(Roboto Light),url("../fonts/roboto/Roboto-Light.eot");src:url("../fonts/roboto/Roboto-Light.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Light.woff2") format("woff2"),url("../fonts/roboto/Roboto-Light.woff") format("woff"),url("../fonts/roboto/Roboto-Light.ttf") format("truetype");font-weight:300}@font-face{font-family:"Roboto";src:local(Roboto Regular),url("../fonts/roboto/Roboto-Regular.eot");src:url("../fonts/roboto/Roboto-Regular.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Regular.woff2") format("woff2"),url("../fonts/roboto/Roboto-Regular.woff") format("woff"),url("../fonts/roboto/Roboto-Regular.ttf") format("truetype");font-weight:400}@font-face{font-family:"Roboto";src:url("../fonts/roboto/Roboto-Medium.eot");src:url("../fonts/roboto/Roboto-Medium.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Medium.woff2") format("woff2"),url("../fonts/roboto/Roboto-Medium.woff") format("woff"),url("../fonts/roboto/Roboto-Medium.ttf") format("truetype");font-weight:500}@font-face{font-family:"Roboto";src:url("../fonts/roboto/Roboto-Bold.eot");src:url("../fonts/roboto/Roboto-Bold.eot?#iefix") format("embedded-opentype"),url("../fonts/roboto/Roboto-Bold.woff2") format("woff2"),url("../fonts/roboto/Roboto-Bold.woff") format("woff"),url("../fonts/roboto/Roboto-Bold.ttf") format("truetype");font-weight:700}a{text-decoration:none}html{line-height:1.5;font-family:"Roboto", sans-serif;font-weight:normal;color:rgba(0,0,0,0.87)}@media only screen and (min-width: 0){html{font-size:14px}}@media only screen and (min-width: 992px){html{font-size:14.5px}}@media only screen and (min-width: 1200px){html{font-size:15px}}h1,h2,h3,h4,h5,h6{font-weight:400;line-height:1.1}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{font-weight:inherit}h1{font-size:4.2rem;line-height:110%;margin:2.1rem 0 1.68rem 0}h2{font-size:3.56rem;line-height:110%;margin:1.78rem 0 1.424rem 0}h3{font-size:2.92rem;line-height:110%;margin:1.46rem 0 1.168rem 0}h4{font-size:2.28rem;line-height:110%;margin:1.14rem 0 .912rem 0}h5{font-size:1.64rem;line-height:110%;margin:.82rem 0 .656rem 0}h6{font-size:1rem;line-height:110%;margin:.5rem 0 .4rem 0}em{font-style:italic}strong{font-weight:500}small{font-size:75%}.light,footer.page-footer .footer-copyright{font-weight:300}.thin{font-weight:200}.flow-text{font-weight:300}@media only screen and (min-width: 360px){.flow-text{font-size:1.2rem}}@media only screen and (min-width: 390px){.flow-text{font-size:1.224rem}}@media only screen and (min-width: 420px){.flow-text{font-size:1.248rem}}@media only screen and (min-width: 450px){.flow-text{font-size:1.272rem}}@media only screen and (min-width: 480px){.flow-text{font-size:1.296rem}}@media only screen and (min-width: 510px){.flow-text{font-size:1.32rem}}@media only screen and (min-width: 540px){.flow-text{font-size:1.344rem}}@media only screen and (min-width: 570px){.flow-text{font-size:1.368rem}}@media only screen and (min-width: 600px){.flow-text{font-size:1.392rem}}@media only screen and (min-width: 630px){.flow-text{font-size:1.416rem}}@media only screen and (min-width: 660px){.flow-text{font-size:1.44rem}}@media only screen and (min-width: 690px){.flow-text{font-size:1.464rem}}@media only screen and (min-width: 720px){.flow-text{font-size:1.488rem}}@media only screen and (min-width: 750px){.flow-text{font-size:1.512rem}}@media only screen and (min-width: 780px){.flow-text{font-size:1.536rem}}@media only screen and (min-width: 810px){.flow-text{font-size:1.56rem}}@media only screen and (min-width: 840px){.flow-text{font-size:1.584rem}}@media only screen and (min-width: 870px){.flow-text{font-size:1.608rem}}@media only screen and (min-width: 900px){.flow-text{font-size:1.632rem}}@media only screen and (min-width: 930px){.flow-text{font-size:1.656rem}}@media only screen and (min-width: 960px){.flow-text{font-size:1.68rem}}@media only screen and (max-width: 360px){.flow-text{font-size:1.2rem}}.scale-transition{transition:-webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important;transition:transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important;transition:transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63), -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important}.scale-transition.scale-out{-webkit-transform:scale(0);transform:scale(0);transition:-webkit-transform .2s !important;transition:transform .2s !important;transition:transform .2s, -webkit-transform .2s !important}.scale-transition.scale-in{-webkit-transform:scale(1);transform:scale(1)}.card-panel{transition:box-shadow .25s;padding:24px;margin:.5rem 0 1rem 0;border-radius:2px;background-color:#fff}.card{position:relative;margin:.5rem 0 1rem 0;background-color:#fff;transition:box-shadow .25s;border-radius:2px}.card .card-title{font-size:24px;font-weight:300}.card .card-title.activator{cursor:pointer}.card.small,.card.medium,.card.large{position:relative}.card.small .card-image,.card.medium .card-image,.card.large .card-image{max-height:60%;overflow:hidden}.card.small .card-image+.card-content,.card.medium .card-image+.card-content,.card.large .card-image+.card-content{max-height:40%}.card.small .card-content,.card.medium .card-content,.card.large .card-content{max-height:100%;overflow:hidden}.card.small .card-action,.card.medium .card-action,.card.large .card-action{position:absolute;bottom:0;left:0;right:0}.card.small{height:300px}.card.medium{height:400px}.card.large{height:500px}.card.horizontal{display:-webkit-flex;display:-ms-flexbox;display:flex}.card.horizontal.small .card-image,.card.horizontal.medium .card-image,.card.horizontal.large .card-image{height:100%;max-height:none;overflow:visible}.card.horizontal.small .card-image img,.card.horizontal.medium .card-image img,.card.horizontal.large .card-image img{height:100%}.card.horizontal .card-image{max-width:50%}.card.horizontal .card-image img{border-radius:2px 0 0 2px;max-width:100%;width:auto}.card.horizontal .card-stacked{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex:1;-ms-flex:1;flex:1;position:relative}.card.horizontal .card-stacked .card-content{-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.card.sticky-action .card-action{z-index:2}.card.sticky-action .card-reveal{z-index:1;padding-bottom:64px}.card .card-image{position:relative}.card .card-image img{display:block;border-radius:2px 2px 0 0;position:relative;left:0;right:0;top:0;bottom:0;width:100%}.card .card-image .card-title{color:#fff;position:absolute;bottom:0;left:0;max-width:100%;padding:24px}.card .card-content{padding:24px;border-radius:0 0 2px 2px}.card .card-content p{margin:0;color:inherit}.card .card-content .card-title{display:block;line-height:32px;margin-bottom:8px}.card .card-content .card-title i{line-height:32px}.card .card-action{position:relative;background-color:inherit;border-top:1px solid rgba(160,160,160,0.2);padding:16px 24px}.card .card-action a:not(.btn):not(.btn-large):not(.btn-large):not(.btn-floating){color:#ffab40;margin-right:24px;transition:color .3s ease;text-transform:uppercase}.card .card-action a:not(.btn):not(.btn-large):not(.btn-large):not(.btn-floating):hover{color:#ffd8a6}.card .card-reveal{padding:24px;position:absolute;background-color:#fff;width:100%;overflow-y:auto;left:0;top:100%;height:100%;z-index:3;display:none}.card .card-reveal .card-title{cursor:pointer;display:block}#toast-container{display:block;position:fixed;z-index:10000}@media only screen and (max-width: 600px){#toast-container{min-width:100%;bottom:0%}}@media only screen and (min-width: 601px) and (max-width: 992px){#toast-container{left:5%;bottom:7%;max-width:90%}}@media only screen and (min-width: 993px){#toast-container{top:10%;right:7%;max-width:86%}}.toast{border-radius:2px;top:35px;width:auto;clear:both;margin-top:10px;position:relative;max-width:100%;height:auto;min-height:48px;line-height:1.5em;word-break:break-all;background-color:#323232;padding:10px 25px;font-size:1.1rem;font-weight:300;color:#fff;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.toast .btn,.toast .btn-large,.toast .btn-flat{margin:0;margin-left:3rem}.toast.rounded{border-radius:24px}@media only screen and (max-width: 600px){.toast{width:100%;border-radius:0}}@media only screen and (min-width: 601px) and (max-width: 992px){.toast{float:left}}@media only screen and (min-width: 993px){.toast{float:right}}.tabs{position:relative;overflow-x:auto;overflow-y:hidden;height:48px;width:100%;background-color:#fff;margin:0 auto;white-space:nowrap}.tabs.tabs-transparent{background-color:transparent}.tabs.tabs-transparent .tab a,.tabs.tabs-transparent .tab.disabled a,.tabs.tabs-transparent .tab.disabled a:hover{color:rgba(255,255,255,0.7)}.tabs.tabs-transparent .tab a:hover,.tabs.tabs-transparent .tab a.active{color:#fff}.tabs.tabs-transparent .indicator{background-color:#fff}.tabs.tabs-fixed-width{display:-webkit-flex;display:-ms-flexbox;display:flex}.tabs.tabs-fixed-width .tab{-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.tabs .tab{display:inline-block;text-align:center;line-height:48px;height:48px;padding:0;margin:0;text-transform:uppercase}.tabs .tab a{color:rgba(238,110,115,0.7);display:block;width:100%;height:100%;padding:0 24px;font-size:14px;text-overflow:ellipsis;overflow:hidden;transition:color .28s ease}.tabs .tab a:hover,.tabs .tab a.active{background-color:transparent;color:#ee6e73}.tabs .tab.disabled a,.tabs .tab.disabled a:hover{color:rgba(238,110,115,0.7);cursor:default}.tabs .indicator{position:absolute;bottom:0;height:2px;background-color:#f6b2b5;will-change:left, right}@media only screen and (max-width: 992px){.tabs{display:-webkit-flex;display:-ms-flexbox;display:flex}.tabs .tab{-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.tabs .tab a{padding:0 12px}}.material-tooltip{padding:10px 8px;font-size:1rem;z-index:2000;background-color:transparent;border-radius:2px;color:#fff;min-height:36px;line-height:120%;opacity:0;position:absolute;text-align:center;max-width:calc(100% - 4px);overflow:hidden;left:0;top:0;pointer-events:none;visibility:hidden}.backdrop{position:absolute;opacity:0;height:7px;width:14px;border-radius:0 0 50% 50%;background-color:#323232;z-index:-1;-webkit-transform-origin:50% 0%;transform-origin:50% 0%;visibility:hidden}.btn,.btn-large,.btn-flat{border:none;border-radius:2px;display:inline-block;height:36px;line-height:36px;padding:0 2rem;text-transform:uppercase;vertical-align:middle;-webkit-tap-highlight-color:transparent}.btn.disabled,.disabled.btn-large,.btn-floating.disabled,.btn-large.disabled,.btn-flat.disabled,.btn:disabled,.btn-large:disabled,.btn-floating:disabled,.btn-large:disabled,.btn-flat:disabled,.btn[disabled],[disabled].btn-large,.btn-floating[disabled],.btn-large[disabled],.btn-flat[disabled]{pointer-events:none;background-color:#DFDFDF !important;box-shadow:none;color:#9F9F9F !important;cursor:default}.btn.disabled:hover,.disabled.btn-large:hover,.btn-floating.disabled:hover,.btn-large.disabled:hover,.btn-flat.disabled:hover,.btn:disabled:hover,.btn-large:disabled:hover,.btn-floating:disabled:hover,.btn-large:disabled:hover,.btn-flat:disabled:hover,.btn[disabled]:hover,[disabled].btn-large:hover,.btn-floating[disabled]:hover,.btn-large[disabled]:hover,.btn-flat[disabled]:hover{background-color:#DFDFDF !important;color:#9F9F9F !important}.btn,.btn-large,.btn-floating,.btn-large,.btn-flat{outline:0}.btn i,.btn-large i,.btn-floating i,.btn-large i,.btn-flat i{font-size:1.3rem;line-height:inherit}.btn:focus,.btn-large:focus,.btn-floating:focus{background-color:#1d7d74}.btn,.btn-large{text-decoration:none;color:#fff;background-color:#26a69a;text-align:center;letter-spacing:.5px;transition:.2s ease-out;cursor:pointer}.btn:hover,.btn-large:hover{background-color:#2bbbad}.btn-floating{display:inline-block;color:#fff;position:relative;overflow:hidden;z-index:1;width:40px;height:40px;line-height:40px;padding:0;background-color:#26a69a;border-radius:50%;transition:.3s;cursor:pointer;vertical-align:middle}.btn-floating:hover{background-color:#26a69a}.btn-floating:before{border-radius:0}.btn-floating.btn-large{width:56px;height:56px}.btn-floating.btn-large i{line-height:56px}.btn-floating.halfway-fab{position:absolute;right:24px;bottom:0;-webkit-transform:translateY(50%);transform:translateY(50%)}.btn-floating.halfway-fab.left{right:auto;left:24px}.btn-floating i{width:inherit;display:inline-block;text-align:center;color:#fff;font-size:1.6rem;line-height:40px}button.btn-floating{border:none}.fixed-action-btn{position:fixed;right:23px;bottom:23px;padding-top:15px;margin-bottom:0;z-index:998}.fixed-action-btn.active ul{visibility:visible}.fixed-action-btn.horizontal{padding:0 0 0 15px}.fixed-action-btn.horizontal ul{text-align:right;right:64px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);height:100%;left:auto;width:500px}.fixed-action-btn.horizontal ul li{display:inline-block;margin:15px 15px 0 0}.fixed-action-btn.toolbar{padding:0;height:56px}.fixed-action-btn.toolbar.active>a i{opacity:0}.fixed-action-btn.toolbar ul{display:-webkit-flex;display:-ms-flexbox;display:flex;top:0;bottom:0}.fixed-action-btn.toolbar ul li{-webkit-flex:1;-ms-flex:1;flex:1;display:inline-block;margin:0;height:100%;transition:none}.fixed-action-btn.toolbar ul li a{display:block;overflow:hidden;position:relative;width:100%;height:100%;background-color:transparent;box-shadow:none;color:#fff;line-height:56px;z-index:1}.fixed-action-btn.toolbar ul li a i{line-height:inherit}.fixed-action-btn ul{left:0;right:0;text-align:center;position:absolute;bottom:64px;margin:0;visibility:hidden}.fixed-action-btn ul li{margin-bottom:15px}.fixed-action-btn ul a.btn-floating{opacity:0}.fixed-action-btn .fab-backdrop{position:absolute;top:0;left:0;z-index:-1;width:40px;height:40px;background-color:#26a69a;border-radius:50%;-webkit-transform:scale(0);transform:scale(0)}.btn-flat{box-shadow:none;background-color:transparent;color:#343434;cursor:pointer;transition:background-color .2s}.btn-flat:focus,.btn-flat:active{background-color:transparent}.btn-flat:focus,.btn-flat:hover{background-color:rgba(0,0,0,0.1);box-shadow:none}.btn-flat:active{background-color:rgba(0,0,0,0.2)}.btn-flat.disabled{background-color:transparent !important;color:#b3b3b3 !important;cursor:default}.btn-large{height:54px;line-height:54px}.btn-large i{font-size:1.6rem}.btn-block{display:block}.dropdown-content{background-color:#fff;margin:0;display:none;min-width:100px;max-height:650px;overflow-y:auto;opacity:0;position:absolute;z-index:999;will-change:width, height}.dropdown-content li{clear:both;color:rgba(0,0,0,0.87);cursor:pointer;min-height:50px;line-height:1.5rem;width:100%;text-align:left;text-transform:none}.dropdown-content li:hover,.dropdown-content li.active,.dropdown-content li.selected{background-color:#eee}.dropdown-content li.active.selected{background-color:#e1e1e1}.dropdown-content li.divider{min-height:0;height:1px}.dropdown-content li>a,.dropdown-content li>span{font-size:16px;color:#26a69a;display:block;line-height:22px;padding:14px 16px}.dropdown-content li>span>label{top:1px;left:0;height:18px}.dropdown-content li>a>i{height:inherit;line-height:inherit}.input-field.col .dropdown-content [type="checkbox"]+label{top:1px;left:0;height:18px}/*!
- * Waves v0.6.0
- * http://fian.my.id/Waves
- *
- * Copyright 2014 Alfiana E. Sibuea and other contributors
- * Released under the MIT license
- * https://github.com/fians/Waves/blob/master/LICENSE
- */.waves-effect{position:relative;cursor:pointer;display:inline-block;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;vertical-align:middle;z-index:1;transition:.3s ease-out}.waves-effect .waves-ripple{position:absolute;border-radius:50%;width:20px;height:20px;margin-top:-10px;margin-left:-10px;opacity:0;background:rgba(0,0,0,0.2);transition:all 0.7s ease-out;transition-property:opacity, -webkit-transform;transition-property:transform, opacity;transition-property:transform, opacity, -webkit-transform;-webkit-transform:scale(0);transform:scale(0);pointer-events:none}.waves-effect.waves-light .waves-ripple{background-color:rgba(255,255,255,0.45)}.waves-effect.waves-red .waves-ripple{background-color:rgba(244,67,54,0.7)}.waves-effect.waves-yellow .waves-ripple{background-color:rgba(255,235,59,0.7)}.waves-effect.waves-orange .waves-ripple{background-color:rgba(255,152,0,0.7)}.waves-effect.waves-purple .waves-ripple{background-color:rgba(156,39,176,0.7)}.waves-effect.waves-green .waves-ripple{background-color:rgba(76,175,80,0.7)}.waves-effect.waves-teal .waves-ripple{background-color:rgba(0,150,136,0.7)}.waves-effect input[type="button"],.waves-effect input[type="reset"],.waves-effect input[type="submit"]{border:0;font-style:normal;font-size:inherit;text-transform:inherit;background:none}.waves-effect img{position:relative;z-index:-1}.waves-notransition{transition:none !important}.waves-circle{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-mask-image:-webkit-radial-gradient(circle, #fff 100%, #000 100%)}.waves-input-wrapper{border-radius:0.2em;vertical-align:bottom}.waves-input-wrapper .waves-button-input{position:relative;top:0;left:0;z-index:1}.waves-circle{text-align:center;width:2.5em;height:2.5em;line-height:2.5em;border-radius:50%;-webkit-mask-image:none}.waves-block{display:block}.waves-effect .waves-ripple{z-index:-1}.modal{display:none;position:fixed;left:0;right:0;background-color:#fafafa;padding:0;max-height:70%;width:55%;margin:auto;overflow-y:auto;border-radius:2px;will-change:top, opacity}@media only screen and (max-width: 992px){.modal{width:80%}}.modal h1,.modal h2,.modal h3,.modal h4{margin-top:0}.modal .modal-content{padding:24px}.modal .modal-close{cursor:pointer}.modal .modal-footer{border-radius:0 0 2px 2px;background-color:#fafafa;padding:4px 6px;height:56px;width:100%}.modal .modal-footer .btn,.modal .modal-footer .btn-large,.modal .modal-footer .btn-flat{float:right;margin:6px 0}.modal-overlay{position:fixed;z-index:999;top:-100px;left:0;bottom:0;right:0;height:125%;width:100%;background:#000;display:none;will-change:opacity}.modal.modal-fixed-footer{padding:0;height:70%}.modal.modal-fixed-footer .modal-content{position:absolute;height:calc(100% - 56px);max-height:100%;width:100%;overflow-y:auto}.modal.modal-fixed-footer .modal-footer{border-top:1px solid rgba(0,0,0,0.1);position:absolute;bottom:0}.modal.bottom-sheet{top:auto;bottom:-100%;margin:0;width:100%;max-height:45%;border-radius:0;will-change:bottom, opacity}.collapsible{border-top:1px solid #ddd;border-right:1px solid #ddd;border-left:1px solid #ddd;margin:.5rem 0 1rem 0}.collapsible-header{display:block;cursor:pointer;min-height:3rem;line-height:3rem;padding:0 1rem;background-color:#fff;border-bottom:1px solid #ddd}.collapsible-header i{width:2rem;font-size:1.6rem;line-height:3rem;display:block;float:left;text-align:center;margin-right:1rem}.collapsible-body{display:none;border-bottom:1px solid #ddd;box-sizing:border-box;padding:2rem}.side-nav .collapsible,.side-nav.fixed .collapsible{border:none;box-shadow:none}.side-nav .collapsible li,.side-nav.fixed .collapsible li{padding:0}.side-nav .collapsible-header,.side-nav.fixed .collapsible-header{background-color:transparent;border:none;line-height:inherit;height:inherit;padding:0 16px}.side-nav .collapsible-header:hover,.side-nav.fixed .collapsible-header:hover{background-color:rgba(0,0,0,0.05)}.side-nav .collapsible-header i,.side-nav.fixed .collapsible-header i{line-height:inherit}.side-nav .collapsible-body,.side-nav.fixed .collapsible-body{border:0;background-color:#fff}.side-nav .collapsible-body li a,.side-nav.fixed .collapsible-body li a{padding:0 23.5px 0 31px}.collapsible.popout{border:none;box-shadow:none}.collapsible.popout>li{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12);margin:0 24px;transition:margin 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94)}.collapsible.popout>li.active{box-shadow:0 5px 11px 0 rgba(0,0,0,0.18),0 4px 15px 0 rgba(0,0,0,0.15);margin:16px 0}.chip{display:inline-block;height:32px;font-size:13px;font-weight:500;color:rgba(0,0,0,0.6);line-height:32px;padding:0 12px;border-radius:16px;background-color:#e4e4e4;margin-bottom:5px;margin-right:5px}.chip img{float:left;margin:0 8px 0 -12px;height:32px;width:32px;border-radius:50%}.chip .close{cursor:pointer;float:right;font-size:16px;line-height:32px;padding-left:8px}.chips{border:none;border-bottom:1px solid #9e9e9e;box-shadow:none;margin:0 0 20px 0;min-height:45px;outline:none;transition:all .3s}.chips.focus{border-bottom:1px solid #26a69a;box-shadow:0 1px 0 0 #26a69a}.chips:hover{cursor:text}.chips .chip.selected{background-color:#26a69a;color:#fff}.chips .input{background:none;border:0;color:rgba(0,0,0,0.6);display:inline-block;font-size:1rem;height:3rem;line-height:32px;outline:0;margin:0;padding:0 !important;width:120px !important}.chips .input:focus{border:0 !important;box-shadow:none !important}.prefix ~ .chips{margin-left:3rem;width:92%;width:calc(100% - 3rem)}.chips:empty ~ label{font-size:0.8rem;-webkit-transform:translateY(-140%);transform:translateY(-140%)}.materialboxed{display:block;cursor:-webkit-zoom-in;cursor:zoom-in;position:relative;transition:opacity .4s;-webkit-backface-visibility:hidden}.materialboxed:hover:not(.active){opacity:.8}.materialboxed.active{cursor:-webkit-zoom-out;cursor:zoom-out}#materialbox-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#292929;z-index:1000;will-change:opacity}.materialbox-caption{position:fixed;display:none;color:#fff;line-height:50px;bottom:0;left:0;width:100%;text-align:center;padding:0% 15%;height:50px;z-index:1000;-webkit-font-smoothing:antialiased}select:focus{outline:1px solid #c9f3ef}button:focus{outline:none;background-color:#2ab7a9}label{font-size:.8rem;color:#9e9e9e}::-webkit-input-placeholder{color:#d1d1d1}:-moz-placeholder{color:#d1d1d1}::-moz-placeholder{color:#d1d1d1}:-ms-input-placeholder{color:#d1d1d1}input:not([type]),input[type=text],input[type=password],input[type=email],input[type=url],input[type=time],input[type=date],input[type=datetime],input[type=datetime-local],input[type=tel],input[type=number],input[type=search],textarea.materialize-textarea{background-color:transparent;border:none;border-bottom:1px solid #9e9e9e;border-radius:0;outline:none;height:3rem;width:100%;font-size:1rem;margin:0 0 20px 0;padding:0;box-shadow:none;box-sizing:content-box;transition:all 0.3s}input:not([type]):disabled,input:not([type])[readonly="readonly"],input[type=text]:disabled,input[type=text][readonly="readonly"],input[type=password]:disabled,input[type=password][readonly="readonly"],input[type=email]:disabled,input[type=email][readonly="readonly"],input[type=url]:disabled,input[type=url][readonly="readonly"],input[type=time]:disabled,input[type=time][readonly="readonly"],input[type=date]:disabled,input[type=date][readonly="readonly"],input[type=datetime]:disabled,input[type=datetime][readonly="readonly"],input[type=datetime-local]:disabled,input[type=datetime-local][readonly="readonly"],input[type=tel]:disabled,input[type=tel][readonly="readonly"],input[type=number]:disabled,input[type=number][readonly="readonly"],input[type=search]:disabled,input[type=search][readonly="readonly"],textarea.materialize-textarea:disabled,textarea.materialize-textarea[readonly="readonly"]{color:rgba(0,0,0,0.26);border-bottom:1px dotted rgba(0,0,0,0.26)}input:not([type]):disabled+label,input:not([type])[readonly="readonly"]+label,input[type=text]:disabled+label,input[type=text][readonly="readonly"]+label,input[type=password]:disabled+label,input[type=password][readonly="readonly"]+label,input[type=email]:disabled+label,input[type=email][readonly="readonly"]+label,input[type=url]:disabled+label,input[type=url][readonly="readonly"]+label,input[type=time]:disabled+label,input[type=time][readonly="readonly"]+label,input[type=date]:disabled+label,input[type=date][readonly="readonly"]+label,input[type=datetime]:disabled+label,input[type=datetime][readonly="readonly"]+label,input[type=datetime-local]:disabled+label,input[type=datetime-local][readonly="readonly"]+label,input[type=tel]:disabled+label,input[type=tel][readonly="readonly"]+label,input[type=number]:disabled+label,input[type=number][readonly="readonly"]+label,input[type=search]:disabled+label,input[type=search][readonly="readonly"]+label,textarea.materialize-textarea:disabled+label,textarea.materialize-textarea[readonly="readonly"]+label{color:rgba(0,0,0,0.26)}input:not([type]):focus:not([readonly]),input[type=text]:focus:not([readonly]),input[type=password]:focus:not([readonly]),input[type=email]:focus:not([readonly]),input[type=url]:focus:not([readonly]),input[type=time]:focus:not([readonly]),input[type=date]:focus:not([readonly]),input[type=datetime]:focus:not([readonly]),input[type=datetime-local]:focus:not([readonly]),input[type=tel]:focus:not([readonly]),input[type=number]:focus:not([readonly]),input[type=search]:focus:not([readonly]),textarea.materialize-textarea:focus:not([readonly]){border-bottom:1px solid #26a69a;box-shadow:0 1px 0 0 #26a69a}input:not([type]):focus:not([readonly])+label,input[type=text]:focus:not([readonly])+label,input[type=password]:focus:not([readonly])+label,input[type=email]:focus:not([readonly])+label,input[type=url]:focus:not([readonly])+label,input[type=time]:focus:not([readonly])+label,input[type=date]:focus:not([readonly])+label,input[type=datetime]:focus:not([readonly])+label,input[type=datetime-local]:focus:not([readonly])+label,input[type=tel]:focus:not([readonly])+label,input[type=number]:focus:not([readonly])+label,input[type=search]:focus:not([readonly])+label,textarea.materialize-textarea:focus:not([readonly])+label{color:#26a69a}input:not([type]).valid,input:not([type]):focus.valid,input[type=text].valid,input[type=text]:focus.valid,input[type=password].valid,input[type=password]:focus.valid,input[type=email].valid,input[type=email]:focus.valid,input[type=url].valid,input[type=url]:focus.valid,input[type=time].valid,input[type=time]:focus.valid,input[type=date].valid,input[type=date]:focus.valid,input[type=datetime].valid,input[type=datetime]:focus.valid,input[type=datetime-local].valid,input[type=datetime-local]:focus.valid,input[type=tel].valid,input[type=tel]:focus.valid,input[type=number].valid,input[type=number]:focus.valid,input[type=search].valid,input[type=search]:focus.valid,textarea.materialize-textarea.valid,textarea.materialize-textarea:focus.valid{border-bottom:1px solid #4CAF50;box-shadow:0 1px 0 0 #4CAF50}input:not([type]).valid+label:after,input:not([type]):focus.valid+label:after,input[type=text].valid+label:after,input[type=text]:focus.valid+label:after,input[type=password].valid+label:after,input[type=password]:focus.valid+label:after,input[type=email].valid+label:after,input[type=email]:focus.valid+label:after,input[type=url].valid+label:after,input[type=url]:focus.valid+label:after,input[type=time].valid+label:after,input[type=time]:focus.valid+label:after,input[type=date].valid+label:after,input[type=date]:focus.valid+label:after,input[type=datetime].valid+label:after,input[type=datetime]:focus.valid+label:after,input[type=datetime-local].valid+label:after,input[type=datetime-local]:focus.valid+label:after,input[type=tel].valid+label:after,input[type=tel]:focus.valid+label:after,input[type=number].valid+label:after,input[type=number]:focus.valid+label:after,input[type=search].valid+label:after,input[type=search]:focus.valid+label:after,textarea.materialize-textarea.valid+label:after,textarea.materialize-textarea:focus.valid+label:after{content:attr(data-success);color:#4CAF50;opacity:1}input:not([type]).invalid,input:not([type]):focus.invalid,input[type=text].invalid,input[type=text]:focus.invalid,input[type=password].invalid,input[type=password]:focus.invalid,input[type=email].invalid,input[type=email]:focus.invalid,input[type=url].invalid,input[type=url]:focus.invalid,input[type=time].invalid,input[type=time]:focus.invalid,input[type=date].invalid,input[type=date]:focus.invalid,input[type=datetime].invalid,input[type=datetime]:focus.invalid,input[type=datetime-local].invalid,input[type=datetime-local]:focus.invalid,input[type=tel].invalid,input[type=tel]:focus.invalid,input[type=number].invalid,input[type=number]:focus.invalid,input[type=search].invalid,input[type=search]:focus.invalid,textarea.materialize-textarea.invalid,textarea.materialize-textarea:focus.invalid{border-bottom:1px solid #F44336;box-shadow:0 1px 0 0 #F44336}input:not([type]).invalid+label:after,input:not([type]):focus.invalid+label:after,input[type=text].invalid+label:after,input[type=text]:focus.invalid+label:after,input[type=password].invalid+label:after,input[type=password]:focus.invalid+label:after,input[type=email].invalid+label:after,input[type=email]:focus.invalid+label:after,input[type=url].invalid+label:after,input[type=url]:focus.invalid+label:after,input[type=time].invalid+label:after,input[type=time]:focus.invalid+label:after,input[type=date].invalid+label:after,input[type=date]:focus.invalid+label:after,input[type=datetime].invalid+label:after,input[type=datetime]:focus.invalid+label:after,input[type=datetime-local].invalid+label:after,input[type=datetime-local]:focus.invalid+label:after,input[type=tel].invalid+label:after,input[type=tel]:focus.invalid+label:after,input[type=number].invalid+label:after,input[type=number]:focus.invalid+label:after,input[type=search].invalid+label:after,input[type=search]:focus.invalid+label:after,textarea.materialize-textarea.invalid+label:after,textarea.materialize-textarea:focus.invalid+label:after{content:attr(data-error);color:#F44336;opacity:1}input:not([type]).validate+label,input[type=text].validate+label,input[type=password].validate+label,input[type=email].validate+label,input[type=url].validate+label,input[type=time].validate+label,input[type=date].validate+label,input[type=datetime].validate+label,input[type=datetime-local].validate+label,input[type=tel].validate+label,input[type=number].validate+label,input[type=search].validate+label,textarea.materialize-textarea.validate+label{width:100%;pointer-events:none}input:not([type])+label:after,input[type=text]+label:after,input[type=password]+label:after,input[type=email]+label:after,input[type=url]+label:after,input[type=time]+label:after,input[type=date]+label:after,input[type=datetime]+label:after,input[type=datetime-local]+label:after,input[type=tel]+label:after,input[type=number]+label:after,input[type=search]+label:after,textarea.materialize-textarea+label:after{display:block;content:"";position:absolute;top:60px;opacity:0;transition:.2s opacity ease-out, .2s color ease-out}.input-field{position:relative;margin-top:1rem}.input-field.inline{display:inline-block;vertical-align:middle;margin-left:5px}.input-field.inline input,.input-field.inline .select-dropdown{margin-bottom:1rem}.input-field.col label{left:.75rem}.input-field.col .prefix ~ label,.input-field.col .prefix ~ .validate ~ label{width:calc(100% - 3rem - 1.5rem)}.input-field label{color:#9e9e9e;position:absolute;top:0.8rem;left:0;font-size:1rem;cursor:text;transition:.2s ease-out}.input-field label:not(.label-icon).active{font-size:.8rem;-webkit-transform:translateY(-140%);transform:translateY(-140%)}.input-field .prefix{position:absolute;width:3rem;font-size:2rem;transition:color .2s}.input-field .prefix.active{color:#26a69a}.input-field .prefix ~ input,.input-field .prefix ~ textarea,.input-field .prefix ~ label,.input-field .prefix ~ .validate ~ label,.input-field .prefix ~ .autocomplete-content{margin-left:3rem;width:92%;width:calc(100% - 3rem)}.input-field .prefix ~ label{margin-left:3rem}@media only screen and (max-width: 992px){.input-field .prefix ~ input{width:86%;width:calc(100% - 3rem)}}@media only screen and (max-width: 600px){.input-field .prefix ~ input{width:80%;width:calc(100% - 3rem)}}.input-field input[type=search]{display:block;line-height:inherit;padding-left:4rem;width:calc(100% - 4rem)}.input-field input[type=search]:focus{background-color:#fff;border:0;box-shadow:none;color:#444}.input-field input[type=search]:focus+label i,.input-field input[type=search]:focus ~ .mdi-navigation-close,.input-field input[type=search]:focus ~ .material-icons{color:#444}.input-field input[type=search]+label{left:1rem}.input-field input[type=search] ~ .mdi-navigation-close,.input-field input[type=search] ~ .material-icons{position:absolute;top:0;right:1rem;color:transparent;cursor:pointer;font-size:2rem;transition:.3s color}textarea{width:100%;height:3rem;background-color:transparent}textarea.materialize-textarea{overflow-y:hidden;padding:.8rem 0 1.6rem 0;resize:none;min-height:3rem}.hiddendiv{display:none;white-space:pre-wrap;word-wrap:break-word;overflow-wrap:break-word;padding-top:1.2rem}.autocomplete-content{margin-top:-15px;display:block;opacity:1;position:static}.autocomplete-content li .highlight{color:#444}.autocomplete-content li img{height:40px;width:40px;margin:5px 15px}[type="radio"]:not(:checked),[type="radio"]:checked{position:absolute;left:-9999px;opacity:0}[type="radio"]:not(:checked)+label,[type="radio"]:checked+label{position:relative;padding-left:35px;cursor:pointer;display:inline-block;height:25px;line-height:25px;font-size:1rem;transition:.28s ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[type="radio"]+label:before,[type="radio"]+label:after{content:'';position:absolute;left:0;top:0;margin:4px;width:16px;height:16px;z-index:0;transition:.28s ease}[type="radio"]:not(:checked)+label:before,[type="radio"]:not(:checked)+label:after,[type="radio"]:checked+label:before,[type="radio"]:checked+label:after,[type="radio"].with-gap:checked+label:before,[type="radio"].with-gap:checked+label:after{border-radius:50%}[type="radio"]:not(:checked)+label:before,[type="radio"]:not(:checked)+label:after{border:2px solid #5a5a5a}[type="radio"]:not(:checked)+label:after{-webkit-transform:scale(0);transform:scale(0)}[type="radio"]:checked+label:before{border:2px solid transparent}[type="radio"]:checked+label:after,[type="radio"].with-gap:checked+label:before,[type="radio"].with-gap:checked+label:after{border:2px solid #26a69a}[type="radio"]:checked+label:after,[type="radio"].with-gap:checked+label:after{background-color:#26a69a}[type="radio"]:checked+label:after{-webkit-transform:scale(1.02);transform:scale(1.02)}[type="radio"].with-gap:checked+label:after{-webkit-transform:scale(0.5);transform:scale(0.5)}[type="radio"].tabbed:focus+label:before{box-shadow:0 0 0 10px rgba(0,0,0,0.1)}[type="radio"].with-gap:disabled:checked+label:before{border:2px solid rgba(0,0,0,0.26)}[type="radio"].with-gap:disabled:checked+label:after{border:none;background-color:rgba(0,0,0,0.26)}[type="radio"]:disabled:not(:checked)+label:before,[type="radio"]:disabled:checked+label:before{background-color:transparent;border-color:rgba(0,0,0,0.26)}[type="radio"]:disabled+label{color:rgba(0,0,0,0.26)}[type="radio"]:disabled:not(:checked)+label:before{border-color:rgba(0,0,0,0.26)}[type="radio"]:disabled:checked+label:after{background-color:rgba(0,0,0,0.26);border-color:#BDBDBD}form p{margin-bottom:10px;text-align:left}form p:last-child{margin-bottom:0}[type="checkbox"]:not(:checked),[type="checkbox"]:checked{position:absolute;left:-9999px;opacity:0}[type="checkbox"]+label{position:relative;padding-left:35px;cursor:pointer;display:inline-block;height:25px;line-height:25px;font-size:1rem;-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-ms-user-select:none}[type="checkbox"]+label:before,[type="checkbox"]:not(.filled-in)+label:after{content:'';position:absolute;top:0;left:0;width:18px;height:18px;z-index:0;border:2px solid #5a5a5a;border-radius:1px;margin-top:2px;transition:.2s}[type="checkbox"]:not(.filled-in)+label:after{border:0;-webkit-transform:scale(0);transform:scale(0)}[type="checkbox"]:not(:checked):disabled+label:before{border:none;background-color:rgba(0,0,0,0.26)}[type="checkbox"].tabbed:focus+label:after{-webkit-transform:scale(1);transform:scale(1);border:0;border-radius:50%;box-shadow:0 0 0 10px rgba(0,0,0,0.1);background-color:rgba(0,0,0,0.1)}[type="checkbox"]:checked+label:before{top:-4px;left:-5px;width:12px;height:22px;border-top:2px solid transparent;border-left:2px solid transparent;border-right:2px solid #26a69a;border-bottom:2px solid #26a69a;-webkit-transform:rotate(40deg);transform:rotate(40deg);-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"]:checked:disabled+label:before{border-right:2px solid rgba(0,0,0,0.26);border-bottom:2px solid rgba(0,0,0,0.26)}[type="checkbox"]:indeterminate+label:before{top:-11px;left:-12px;width:10px;height:22px;border-top:none;border-left:none;border-right:2px solid #26a69a;border-bottom:none;-webkit-transform:rotate(90deg);transform:rotate(90deg);-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"]:indeterminate:disabled+label:before{border-right:2px solid rgba(0,0,0,0.26);background-color:transparent}[type="checkbox"].filled-in+label:after{border-radius:2px}[type="checkbox"].filled-in+label:before,[type="checkbox"].filled-in+label:after{content:'';left:0;position:absolute;transition:border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s;z-index:1}[type="checkbox"].filled-in:not(:checked)+label:before{width:0;height:0;border:3px solid transparent;left:6px;top:10px;-webkit-transform:rotateZ(37deg);transform:rotateZ(37deg);-webkit-transform-origin:20% 40%;transform-origin:100% 100%}[type="checkbox"].filled-in:not(:checked)+label:after{height:20px;width:20px;background-color:transparent;border:2px solid #5a5a5a;top:0px;z-index:0}[type="checkbox"].filled-in:checked+label:before{top:0;left:1px;width:8px;height:13px;border-top:2px solid transparent;border-left:2px solid transparent;border-right:2px solid #fff;border-bottom:2px solid #fff;-webkit-transform:rotateZ(37deg);transform:rotateZ(37deg);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"].filled-in:checked+label:after{top:0;width:20px;height:20px;border:2px solid #26a69a;background-color:#26a69a;z-index:0}[type="checkbox"].filled-in.tabbed:focus+label:after{border-radius:2px;border-color:#5a5a5a;background-color:rgba(0,0,0,0.1)}[type="checkbox"].filled-in.tabbed:checked:focus+label:after{border-radius:2px;background-color:#26a69a;border-color:#26a69a}[type="checkbox"].filled-in:disabled:not(:checked)+label:before{background-color:transparent;border:2px solid transparent}[type="checkbox"].filled-in:disabled:not(:checked)+label:after{border-color:transparent;background-color:#BDBDBD}[type="checkbox"].filled-in:disabled:checked+label:before{background-color:transparent}[type="checkbox"].filled-in:disabled:checked+label:after{background-color:#BDBDBD;border-color:#BDBDBD}.switch,.switch *{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-ms-user-select:none}.switch label{cursor:pointer}.switch label input[type=checkbox]{opacity:0;width:0;height:0}.switch label input[type=checkbox]:checked+.lever{background-color:#84c7c1}.switch label input[type=checkbox]:checked+.lever:after{background-color:#26a69a;left:24px}.switch label .lever{content:"";display:inline-block;position:relative;width:40px;height:15px;background-color:#818181;border-radius:15px;margin-right:10px;transition:background 0.3s ease;vertical-align:middle;margin:0 16px}.switch label .lever:after{content:"";position:absolute;display:inline-block;width:21px;height:21px;background-color:#F1F1F1;border-radius:21px;box-shadow:0 1px 3px 1px rgba(0,0,0,0.4);left:-5px;top:-3px;transition:left 0.3s ease, background .3s ease, box-shadow 0.1s ease}input[type=checkbox]:checked:not(:disabled) ~ .lever:active::after,input[type=checkbox]:checked:not(:disabled).tabbed:focus ~ .lever::after{box-shadow:0 1px 3px 1px rgba(0,0,0,0.4),0 0 0 15px rgba(38,166,154,0.1)}input[type=checkbox]:not(:disabled) ~ .lever:active:after,input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::after{box-shadow:0 1px 3px 1px rgba(0,0,0,0.4),0 0 0 15px rgba(0,0,0,0.08)}.switch input[type=checkbox][disabled]+.lever{cursor:default}.switch label input[type=checkbox][disabled]+.lever:after,.switch label input[type=checkbox][disabled]:checked+.lever:after{background-color:#BDBDBD}select{display:none}select.browser-default{display:block}select{background-color:rgba(255,255,255,0.9);width:100%;padding:5px;border:1px solid #f2f2f2;border-radius:2px;height:3rem}.select-label{position:absolute}.select-wrapper{position:relative}.select-wrapper input.select-dropdown{position:relative;cursor:pointer;background-color:transparent;border:none;border-bottom:1px solid #9e9e9e;outline:none;height:3rem;line-height:3rem;width:100%;font-size:1rem;margin:0 0 20px 0;padding:0;display:block}.select-wrapper span.caret{color:initial;position:absolute;right:0;top:0;bottom:0;height:10px;margin:auto 0;font-size:10px;line-height:10px}.select-wrapper span.caret.disabled{color:rgba(0,0,0,0.26)}.select-wrapper+label{position:absolute;top:-14px;font-size:.8rem}select:disabled{color:rgba(0,0,0,0.3)}.select-wrapper input.select-dropdown:disabled{color:rgba(0,0,0,0.3);cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;border-bottom:1px solid rgba(0,0,0,0.3)}.select-wrapper i{color:rgba(0,0,0,0.3)}.select-dropdown li.disabled,.select-dropdown li.disabled>span,.select-dropdown li.optgroup{color:rgba(0,0,0,0.3);background-color:transparent}.prefix ~ .select-wrapper{margin-left:3rem;width:92%;width:calc(100% - 3rem)}.prefix ~ label{margin-left:3rem}.select-dropdown li img{height:40px;width:40px;margin:5px 15px;float:right}.select-dropdown li.optgroup{border-top:1px solid #eee}.select-dropdown li.optgroup.selected>span{color:rgba(0,0,0,0.7)}.select-dropdown li.optgroup>span{color:rgba(0,0,0,0.4)}.select-dropdown li.optgroup ~ li.optgroup-option{padding-left:1rem}.file-field{position:relative}.file-field .file-path-wrapper{overflow:hidden;padding-left:10px}.file-field input.file-path{width:100%}.file-field .btn,.file-field .btn-large{float:left;height:3rem;line-height:3rem}.file-field span{cursor:pointer}.file-field input[type=file]{position:absolute;top:0;right:0;left:0;bottom:0;width:100%;margin:0;padding:0;font-size:20px;cursor:pointer;opacity:0;filter:alpha(opacity=0)}.range-field{position:relative}input[type=range],input[type=range]+.thumb{cursor:pointer}input[type=range]{position:relative;background-color:transparent;border:none;outline:none;width:100%;margin:15px 0;padding:0}input[type=range]:focus{outline:none}input[type=range]+.thumb{position:absolute;border:none;height:0;width:0;border-radius:50%;background-color:#26a69a;top:10px;margin-left:-6px;-webkit-transform-origin:50% 50%;transform-origin:50% 50%;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}input[type=range]+.thumb .value{display:block;width:30px;text-align:center;color:#26a69a;font-size:0;-webkit-transform:rotate(45deg);transform:rotate(45deg)}input[type=range]+.thumb.active{border-radius:50% 50% 50% 0}input[type=range]+.thumb.active .value{color:#fff;margin-left:-1px;margin-top:8px;font-size:10px}input[type=range]{-webkit-appearance:none}input[type=range]::-webkit-slider-runnable-track{height:3px;background:#c2c0c2;border:none}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;border:none;height:14px;width:14px;border-radius:50%;background-color:#26a69a;-webkit-transform-origin:50% 50%;transform-origin:50% 50%;margin:-5px 0 0 0;transition:.3s}input[type=range]:focus::-webkit-slider-runnable-track{background:#ccc}input[type=range]{border:1px solid white}input[type=range]::-moz-range-track{height:3px;background:#ddd;border:none}input[type=range]::-moz-range-thumb{border:none;height:14px;width:14px;border-radius:50%;background:#26a69a;margin-top:-5px}input[type=range]:-moz-focusring{outline:1px solid #fff;outline-offset:-1px}input[type=range]:focus::-moz-range-track{background:#ccc}input[type=range]::-ms-track{height:3px;background:transparent;border-color:transparent;border-width:6px 0;color:transparent}input[type=range]::-ms-fill-lower{background:#777}input[type=range]::-ms-fill-upper{background:#ddd}input[type=range]::-ms-thumb{border:none;height:14px;width:14px;border-radius:50%;background:#26a69a}input[type=range]:focus::-ms-fill-lower{background:#888}input[type=range]:focus::-ms-fill-upper{background:#ccc}.table-of-contents.fixed{position:fixed}.table-of-contents li{padding:2px 0}.table-of-contents a{display:inline-block;font-weight:300;color:#757575;padding-left:20px;height:1.5rem;line-height:1.5rem;letter-spacing:.4;display:inline-block}.table-of-contents a:hover{color:#a8a8a8;padding-left:19px;border-left:1px solid #ee6e73}.table-of-contents a.active{font-weight:500;padding-left:18px;border-left:2px solid #ee6e73}.side-nav{position:fixed;width:300px;left:0;top:0;margin:0;-webkit-transform:translateX(-100%);transform:translateX(-100%);height:100%;height:calc(100% + 60px);height:-moz-calc(100%);padding-bottom:60px;background-color:#fff;z-index:999;overflow-y:auto;will-change:transform;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateX(-105%);transform:translateX(-105%)}.side-nav.right-aligned{right:0;-webkit-transform:translateX(105%);transform:translateX(105%);left:auto;-webkit-transform:translateX(100%);transform:translateX(100%)}.side-nav .collapsible{margin:0}.side-nav li{float:none;line-height:48px}.side-nav li.active{background-color:rgba(0,0,0,0.05)}.side-nav a{color:rgba(0,0,0,0.87);display:block;font-size:14px;font-weight:500;height:48px;line-height:48px;padding:0 32px}.side-nav a:hover{background-color:rgba(0,0,0,0.05)}.side-nav a.btn,.side-nav a.btn-large,.side-nav a.btn-large,.side-nav a.btn-flat,.side-nav a.btn-floating{margin:10px 15px}.side-nav a.btn,.side-nav a.btn-large,.side-nav a.btn-large,.side-nav a.btn-floating{color:#fff}.side-nav a.btn-flat{color:#343434}.side-nav a.btn:hover,.side-nav a.btn-large:hover,.side-nav a.btn-large:hover{background-color:#2bbbad}.side-nav a.btn-floating:hover{background-color:#26a69a}.side-nav li>a>i,.side-nav li>a>[class^="mdi-"],.side-nav li>a>[class*="mdi-"],.side-nav li>a>i.material-icons{float:left;height:48px;line-height:48px;margin:0 32px 0 0;width:24px;color:rgba(0,0,0,0.54)}.side-nav .divider{margin:8px 0 0 0}.side-nav .subheader{cursor:initial;pointer-events:none;color:rgba(0,0,0,0.54);font-size:14px;font-weight:500;line-height:48px}.side-nav .subheader:hover{background-color:transparent}.side-nav .userView{position:relative;padding:32px 32px 0;margin-bottom:8px}.side-nav .userView>a{height:auto;padding:0}.side-nav .userView>a:hover{background-color:transparent}.side-nav .userView .background{overflow:hidden;position:absolute;top:0;right:0;bottom:0;left:0;z-index:-1}.side-nav .userView .circle,.side-nav .userView .name,.side-nav .userView .email{display:block}.side-nav .userView .circle{height:64px;width:64px}.side-nav .userView .name,.side-nav .userView .email{font-size:14px;line-height:24px}.side-nav .userView .name{margin-top:16px;font-weight:500}.side-nav .userView .email{padding-bottom:16px;font-weight:400}.drag-target{height:100%;width:10px;position:fixed;top:0;z-index:998}.side-nav.fixed{left:0;-webkit-transform:translateX(0);transform:translateX(0);position:fixed}.side-nav.fixed.right-aligned{right:0;left:auto}@media only screen and (max-width: 992px){.side-nav.fixed{-webkit-transform:translateX(-105%);transform:translateX(-105%)}.side-nav.fixed.right-aligned{-webkit-transform:translateX(105%);transform:translateX(105%)}.side-nav a{padding:0 16px}.side-nav .userView{padding:16px 16px 0}}.side-nav .collapsible-body>ul:not(.collapsible)>li.active,.side-nav.fixed .collapsible-body>ul:not(.collapsible)>li.active{background-color:#ee6e73}.side-nav .collapsible-body>ul:not(.collapsible)>li.active a,.side-nav.fixed .collapsible-body>ul:not(.collapsible)>li.active a{color:#fff}#sidenav-overlay{position:fixed;top:0;left:0;right:0;height:120vh;background-color:rgba(0,0,0,0.5);z-index:997;will-change:opacity}.preloader-wrapper{display:inline-block;position:relative;width:48px;height:48px}.preloader-wrapper.small{width:36px;height:36px}.preloader-wrapper.big{width:64px;height:64px}.preloader-wrapper.active{-webkit-animation:container-rotate 1568ms linear infinite;animation:container-rotate 1568ms linear infinite}@-webkit-keyframes container-rotate{to{-webkit-transform:rotate(360deg)}}@keyframes container-rotate{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-layer{position:absolute;width:100%;height:100%;opacity:0;border-color:#26a69a}.spinner-blue,.spinner-blue-only{border-color:#4285f4}.spinner-red,.spinner-red-only{border-color:#db4437}.spinner-yellow,.spinner-yellow-only{border-color:#f4b400}.spinner-green,.spinner-green-only{border-color:#0f9d58}.active .spinner-layer.spinner-blue{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer.spinner-red{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer.spinner-yellow{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer.spinner-green{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer,.active .spinner-layer.spinner-blue-only,.active .spinner-layer.spinner-red-only,.active .spinner-layer.spinner-yellow-only,.active .spinner-layer.spinner-green-only{opacity:1;-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}@-webkit-keyframes fill-unfill-rotate{12.5%{-webkit-transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg)}to{-webkit-transform:rotate(1080deg)}}@keyframes fill-unfill-rotate{12.5%{-webkit-transform:rotate(135deg);transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg);transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg);transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg);transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg);transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg);transform:rotate(945deg)}to{-webkit-transform:rotate(1080deg);transform:rotate(1080deg)}}@-webkit-keyframes blue-fade-in-out{from{opacity:1}25%{opacity:1}26%{opacity:0}89%{opacity:0}90%{opacity:1}100%{opacity:1}}@keyframes blue-fade-in-out{from{opacity:1}25%{opacity:1}26%{opacity:0}89%{opacity:0}90%{opacity:1}100%{opacity:1}}@-webkit-keyframes red-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:1}50%{opacity:1}51%{opacity:0}}@keyframes red-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:1}50%{opacity:1}51%{opacity:0}}@-webkit-keyframes yellow-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:1}75%{opacity:1}76%{opacity:0}}@keyframes yellow-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:1}75%{opacity:1}76%{opacity:0}}@-webkit-keyframes green-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:1}90%{opacity:1}100%{opacity:0}}@keyframes green-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:1}90%{opacity:1}100%{opacity:0}}.gap-patch{position:absolute;top:0;left:45%;width:10%;height:100%;overflow:hidden;border-color:inherit}.gap-patch .circle{width:1000%;left:-450%}.circle-clipper{display:inline-block;position:relative;width:50%;height:100%;overflow:hidden;border-color:inherit}.circle-clipper .circle{width:200%;height:100%;border-width:3px;border-style:solid;border-color:inherit;border-bottom-color:transparent !important;border-radius:50%;-webkit-animation:none;animation:none;position:absolute;top:0;right:0;bottom:0}.circle-clipper.left .circle{left:0;border-right-color:transparent !important;-webkit-transform:rotate(129deg);transform:rotate(129deg)}.circle-clipper.right .circle{left:-100%;border-left-color:transparent !important;-webkit-transform:rotate(-129deg);transform:rotate(-129deg)}.active .circle-clipper.left .circle{-webkit-animation:left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .circle-clipper.right .circle{-webkit-animation:right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}@-webkit-keyframes left-spin{from{-webkit-transform:rotate(130deg)}50%{-webkit-transform:rotate(-5deg)}to{-webkit-transform:rotate(130deg)}}@keyframes left-spin{from{-webkit-transform:rotate(130deg);transform:rotate(130deg)}50%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(130deg);transform:rotate(130deg)}}@-webkit-keyframes right-spin{from{-webkit-transform:rotate(-130deg)}50%{-webkit-transform:rotate(5deg)}to{-webkit-transform:rotate(-130deg)}}@keyframes right-spin{from{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}50%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}to{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}}#spinnerContainer.cooldown{-webkit-animation:container-rotate 1568ms linear infinite,fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1);animation:container-rotate 1568ms linear infinite,fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1)}@-webkit-keyframes fade-out{from{opacity:1}to{opacity:0}}@keyframes fade-out{from{opacity:1}to{opacity:0}}.slider{position:relative;height:400px;width:100%}.slider.fullscreen{height:100%;width:100%;position:absolute;top:0;left:0;right:0;bottom:0}.slider.fullscreen ul.slides{height:100%}.slider.fullscreen ul.indicators{z-index:2;bottom:30px}.slider .slides{background-color:#9e9e9e;margin:0;height:400px}.slider .slides li{opacity:0;position:absolute;top:0;left:0;z-index:1;width:100%;height:inherit;overflow:hidden}.slider .slides li img{height:100%;width:100%;background-size:cover;background-position:center}.slider .slides li .caption{color:#fff;position:absolute;top:15%;left:15%;width:70%;opacity:0}.slider .slides li .caption p{color:#e0e0e0}.slider .slides li.active{z-index:2}.slider .indicators{position:absolute;text-align:center;left:0;right:0;bottom:0;margin:0}.slider .indicators .indicator-item{display:inline-block;position:relative;cursor:pointer;height:16px;width:16px;margin:0 12px;background-color:#e0e0e0;transition:background-color .3s;border-radius:50%}.slider .indicators .indicator-item.active{background-color:#4CAF50}.carousel{overflow:hidden;position:relative;width:100%;height:400px;-webkit-perspective:500px;perspective:500px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transform-origin:0% 50%;transform-origin:0% 50%}.carousel.carousel-slider{top:0;left:0;height:0}.carousel.carousel-slider .carousel-fixed-item{position:absolute;left:0;right:0;bottom:20px;z-index:1}.carousel.carousel-slider .carousel-fixed-item.with-indicators{bottom:68px}.carousel.carousel-slider .carousel-item{width:100%;height:100%;min-height:400px;position:absolute;top:0;left:0}.carousel.carousel-slider .carousel-item h2{font-size:24px;font-weight:500;line-height:32px}.carousel.carousel-slider .carousel-item p{font-size:15px}.carousel .carousel-item{display:none;width:200px;height:200px;position:absolute;top:0;left:0}.carousel .carousel-item img{width:100%}.carousel .indicators{position:absolute;text-align:center;left:0;right:0;bottom:0;margin:0}.carousel .indicators .indicator-item{display:inline-block;position:relative;cursor:pointer;height:8px;width:8px;margin:24px 4px;background-color:rgba(255,255,255,0.5);transition:background-color .3s;border-radius:50%}.carousel .indicators .indicator-item.active{background-color:#fff}.picker{font-size:16px;text-align:left;line-height:1.2;color:#000000;position:absolute;z-index:10000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.picker__input{cursor:default}.picker__input.picker__input--active{border-color:#0089ec}.picker__holder{width:100%;overflow-y:auto;-webkit-overflow-scrolling:touch}/*!
- * Default mobile-first, responsive styling for pickadate.js
- * Demo: http://amsul.github.io/pickadate.js
- */.picker__holder,.picker__frame{bottom:0;left:0;right:0;top:100%}.picker__holder{position:fixed;transition:background 0.15s ease-out, top 0s 0.15s;-webkit-backface-visibility:hidden}.picker__frame{position:absolute;margin:0 auto;min-width:256px;width:300px;max-height:350px;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);-moz-opacity:0;opacity:0;transition:all 0.15s ease-out}@media (min-height: 28.875em){.picker__frame{overflow:visible;top:auto;bottom:-100%;max-height:80%}}@media (min-height: 40.125em){.picker__frame{margin-bottom:7.5%}}.picker__wrap{display:table;width:100%;height:100%}@media (min-height: 28.875em){.picker__wrap{display:block}}.picker__box{background:#ffffff;display:table-cell;vertical-align:middle}@media (min-height: 28.875em){.picker__box{display:block;border:1px solid #777777;border-top-color:#898989;border-bottom-width:0;border-radius:5px 5px 0 0;box-shadow:0 12px 36px 16px rgba(0,0,0,0.24)}}.picker--opened .picker__holder{top:0;background:transparent;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E000000,endColorstr=#1E000000)";zoom:1;background:rgba(0,0,0,0.32);transition:background 0.15s ease-out}.picker--opened .picker__frame{top:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);-moz-opacity:1;opacity:1}@media (min-height: 35.875em){.picker--opened .picker__frame{top:10%;bottom:auto}}.picker__input.picker__input--active{border-color:#E3F2FD}.picker__frame{margin:0 auto;max-width:325px}@media (min-height: 38.875em){.picker--opened .picker__frame{top:10%;bottom:auto}}.picker__box{padding:0 1em}.picker__header{text-align:center;position:relative;margin-top:.75em}.picker__month,.picker__year{display:inline-block;margin-left:.25em;margin-right:.25em}.picker__select--month,.picker__select--year{height:2em;padding:0;margin-left:.25em;margin-right:.25em}.picker__select--month.browser-default{display:inline;background-color:#FFFFFF;width:40%}.picker__select--year.browser-default{display:inline;background-color:#FFFFFF;width:26%}.picker__select--month:focus,.picker__select--year:focus{border-color:rgba(0,0,0,0.05)}.picker__nav--prev,.picker__nav--next{position:absolute;padding:.5em 1.25em;width:1em;height:1em;box-sizing:content-box;top:-0.25em}.picker__nav--prev{left:-1em;padding-right:1.25em}.picker__nav--next{right:-1em;padding-left:1.25em}.picker__nav--disabled,.picker__nav--disabled:hover,.picker__nav--disabled:before,.picker__nav--disabled:before:hover{cursor:default;background:none;border-right-color:#f5f5f5;border-left-color:#f5f5f5}.picker__table{text-align:center;border-collapse:collapse;border-spacing:0;table-layout:fixed;font-size:1rem;width:100%;margin-top:.75em;margin-bottom:.5em}.picker__table th,.picker__table td{text-align:center}.picker__table td{margin:0;padding:0}.picker__weekday{width:14.285714286%;font-size:.75em;padding-bottom:.25em;color:#999999;font-weight:500}@media (min-height: 33.875em){.picker__weekday{padding-bottom:.5em}}.picker__day--today{position:relative;color:#595959;letter-spacing:-.3;padding:.75rem 0;font-weight:400;border:1px solid transparent}.picker__day--disabled:before{border-top-color:#aaaaaa}.picker__day--infocus:hover{cursor:pointer;color:#000;font-weight:500}.picker__day--outfocus{display:none;padding:.75rem 0;color:#fff}.picker__day--outfocus:hover{cursor:pointer;color:#dddddd;font-weight:500}.picker__day--highlighted:hover,.picker--focused .picker__day--highlighted{cursor:pointer}.picker__day--selected,.picker__day--selected:hover,.picker--focused .picker__day--selected{border-radius:50%;-webkit-transform:scale(0.75);transform:scale(0.75);background:#0089ec;color:#ffffff}.picker__day--disabled,.picker__day--disabled:hover,.picker--focused .picker__day--disabled{background:#f5f5f5;border-color:#f5f5f5;color:#dddddd;cursor:default}.picker__day--highlighted.picker__day--disabled,.picker__day--highlighted.picker__day--disabled:hover{background:#bbbbbb}.picker__footer{text-align:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.picker__button--today,.picker__button--clear,.picker__button--close{border:1px solid #ffffff;background:#ffffff;font-size:.8em;padding:.66em 0;font-weight:bold;width:33%;display:inline-block;vertical-align:bottom}.picker__button--today:hover,.picker__button--clear:hover,.picker__button--close:hover{cursor:pointer;color:#000000;background:#b1dcfb;border-bottom-color:#b1dcfb}.picker__button--today:focus,.picker__button--clear:focus,.picker__button--close:focus{background:#b1dcfb;border-color:rgba(0,0,0,0.05);outline:none}.picker__button--today:before,.picker__button--clear:before,.picker__button--close:before{position:relative;display:inline-block;height:0}.picker__button--today:before,.picker__button--clear:before{content:" ";margin-right:.45em}.picker__button--today:before{top:-0.05em;width:0;border-top:0.66em solid #0059bc;border-left:.66em solid transparent}.picker__button--clear:before{top:-0.25em;width:.66em;border-top:3px solid #ee2200}.picker__button--close:before{content:"\D7";top:-0.1em;vertical-align:top;font-size:1.1em;margin-right:.35em;color:#777777}.picker__button--today[disabled],.picker__button--today[disabled]:hover{background:#f5f5f5;border-color:#f5f5f5;color:#dddddd;cursor:default}.picker__button--today[disabled]:before{border-top-color:#aaaaaa}.picker__box{border-radius:2px;overflow:hidden}.picker__date-display{text-align:center;background-color:#26a69a;color:#fff;padding-bottom:15px;font-weight:300}.picker__nav--prev:hover,.picker__nav--next:hover{cursor:pointer;color:#000000;background:#a1ded8}.picker__weekday-display{background-color:#1f897f;padding:10px;font-weight:200;letter-spacing:.5;font-size:1rem;margin-bottom:15px}.picker__month-display{text-transform:uppercase;font-size:2rem}.picker__day-display{font-size:4.5rem;font-weight:400}.picker__year-display{font-size:1.8rem;color:rgba(255,255,255,0.4)}.picker__box{padding:0}.picker__calendar-container{padding:0 1rem}.picker__calendar-container thead{border:none}.picker__table{margin-top:0;margin-bottom:.5em}.picker__day--infocus{color:#595959;letter-spacing:-.3;padding:.75rem 0;font-weight:400;border:1px solid transparent}.picker__day.picker__day--today{color:#26a69a}.picker__day.picker__day--today.picker__day--selected{color:#fff}.picker__weekday{font-size:.9rem}.picker__day--selected,.picker__day--selected:hover,.picker--focused .picker__day--selected{border-radius:50%;-webkit-transform:scale(0.9);transform:scale(0.9);background-color:#26a69a;color:#ffffff}.picker__day--selected.picker__day--outfocus,.picker__day--selected:hover.picker__day--outfocus,.picker--focused .picker__day--selected.picker__day--outfocus{background-color:#a1ded8}.picker__footer{text-align:right;padding:5px 10px}.picker__close,.picker__today{font-size:1.1rem;padding:0 1rem;color:#26a69a}.picker__nav--prev:before,.picker__nav--next:before{content:" ";border-top:.5em solid transparent;border-bottom:.5em solid transparent;border-right:0.75em solid #676767;width:0;height:0;display:block;margin:0 auto}.picker__nav--next:before{border-right:0;border-left:0.75em solid #676767}button.picker__today:focus,button.picker__clear:focus,button.picker__close:focus{background-color:#a1ded8}.picker__list{list-style:none;padding:0.75em 0 4.2em;margin:0}.picker__list-item{border-bottom:1px solid #dddddd;border-top:1px solid #dddddd;margin-bottom:-1px;position:relative;background:#ffffff;padding:.75em 1.25em}@media (min-height: 46.75em){.picker__list-item{padding:.5em 1em}}.picker__list-item:hover{cursor:pointer;color:#000000;background:#b1dcfb;border-color:#0089ec;z-index:10}.picker__list-item--highlighted{border-color:#0089ec;z-index:10}.picker__list-item--highlighted:hover,.picker--focused .picker__list-item--highlighted{cursor:pointer;color:#000000;background:#b1dcfb}.picker__list-item--selected,.picker__list-item--selected:hover,.picker--focused .picker__list-item--selected{background:#0089ec;color:#ffffff;z-index:10}.picker__list-item--disabled,.picker__list-item--disabled:hover,.picker--focused .picker__list-item--disabled{background:#f5f5f5;border-color:#f5f5f5;color:#dddddd;cursor:default;border-color:#dddddd;z-index:auto}.picker--time .picker__button--clear{display:block;width:80%;margin:1em auto 0;padding:1em 1.25em;background:none;border:0;font-weight:500;font-size:.67em;text-align:center;text-transform:uppercase;color:#666}.picker--time .picker__button--clear:hover,.picker--time .picker__button--clear:focus{color:#000000;background:#b1dcfb;background:#ee2200;border-color:#ee2200;cursor:pointer;color:#ffffff;outline:none}.picker--time .picker__button--clear:before{top:-0.25em;color:#666;font-size:1.25em;font-weight:bold}.picker--time .picker__button--clear:hover:before,.picker--time .picker__button--clear:focus:before{color:#ffffff}.picker--time .picker__frame{min-width:256px;max-width:320px}.picker--time .picker__box{font-size:1em;background:#f2f2f2;padding:0}@media (min-height: 40.125em){.picker--time .picker__box{margin-bottom:5em}}
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/.DS_Store b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/.DS_Store
deleted file mode 100644 (file)
index ae0d28e..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/.DS_Store and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.eot b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.eot
deleted file mode 100644 (file)
index b73776e..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.eot and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.ttf b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.ttf
deleted file mode 100644 (file)
index 68822ca..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.ttf and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.woff b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.woff
deleted file mode 100644 (file)
index 1f75afd..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.woff and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.woff2 b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.woff2
deleted file mode 100644 (file)
index 350d1c3..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Bold.woff2 and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.eot b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.eot
deleted file mode 100644 (file)
index 072cdc4..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.eot and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.ttf b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.ttf
deleted file mode 100644 (file)
index aa45340..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.ttf and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.woff b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.woff
deleted file mode 100644 (file)
index 3480c6c..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.woff and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.woff2 b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.woff2
deleted file mode 100644 (file)
index 9a4d98c..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Light.woff2 and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.eot b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.eot
deleted file mode 100644 (file)
index f9ad995..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.eot and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.ttf b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.ttf
deleted file mode 100644 (file)
index a3c1a1f..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.ttf and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.woff b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.woff
deleted file mode 100644 (file)
index 1186773..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.woff and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.woff2 b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.woff2
deleted file mode 100644 (file)
index d10a592..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Medium.woff2 and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.eot b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.eot
deleted file mode 100644 (file)
index 9b5e8e4..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.eot and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.ttf b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.ttf
deleted file mode 100644 (file)
index 0e58508..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.ttf and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.woff b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.woff
deleted file mode 100644 (file)
index f823258..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.woff and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.woff2 b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.woff2
deleted file mode 100644 (file)
index b7082ef..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Regular.woff2 and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.eot b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.eot
deleted file mode 100644 (file)
index 2284a3b..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.eot and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.ttf b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.ttf
deleted file mode 100644 (file)
index 8779333..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.ttf and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.woff b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.woff
deleted file mode 100644 (file)
index 2a98c1e..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.woff and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.woff2 b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.woff2
deleted file mode 100644 (file)
index a38025a..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/fonts/roboto/Roboto-Thin.woff2 and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/js/materialize.js b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/js/materialize.js
deleted file mode 100644 (file)
index 8c994c4..0000000
+++ /dev/null
@@ -1,8031 +0,0 @@
-/*!
- * Materialize v0.98.0 (http://materializecss.com)
- * Copyright 2014-2015 Materialize
- * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE)
- */
-// Check for jQuery.
-if (typeof(jQuery) === 'undefined') {
-  var jQuery;
-  // Check if require is a defined function.
-  if (typeof(require) === 'function') {
-    jQuery = $ = require('jquery');
-  // Else use the dollar sign alias.
-  } else {
-    jQuery = $;
-  }
-}
-;/*
- * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
- *
- * Uses the built in easing capabilities added In jQuery 1.1
- * to offer multiple easing options
- *
- * TERMS OF USE - jQuery Easing
- *
- * Open source under the BSD License.
- *
- * Copyright © 2008 George McGinley Smith
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * Neither the name of the author nor the names of contributors may be used to endorse
- * or promote products derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- *
-*/
-
-// t: current time, b: begInnIng value, c: change In value, d: duration
-jQuery.easing['jswing'] = jQuery.easing['swing'];
-
-jQuery.extend( jQuery.easing,
-{
-       def: 'easeOutQuad',
-       swing: function (x, t, b, c, d) {
-               //alert(jQuery.easing.default);
-               return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
-       },
-       easeInQuad: function (x, t, b, c, d) {
-               return c*(t/=d)*t + b;
-       },
-       easeOutQuad: function (x, t, b, c, d) {
-               return -c *(t/=d)*(t-2) + b;
-       },
-       easeInOutQuad: function (x, t, b, c, d) {
-               if ((t/=d/2) < 1) return c/2*t*t + b;
-               return -c/2 * ((--t)*(t-2) - 1) + b;
-       },
-       easeInCubic: function (x, t, b, c, d) {
-               return c*(t/=d)*t*t + b;
-       },
-       easeOutCubic: function (x, t, b, c, d) {
-               return c*((t=t/d-1)*t*t + 1) + b;
-       },
-       easeInOutCubic: function (x, t, b, c, d) {
-               if ((t/=d/2) < 1) return c/2*t*t*t + b;
-               return c/2*((t-=2)*t*t + 2) + b;
-       },
-       easeInQuart: function (x, t, b, c, d) {
-               return c*(t/=d)*t*t*t + b;
-       },
-       easeOutQuart: function (x, t, b, c, d) {
-               return -c * ((t=t/d-1)*t*t*t - 1) + b;
-       },
-       easeInOutQuart: function (x, t, b, c, d) {
-               if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
-               return -c/2 * ((t-=2)*t*t*t - 2) + b;
-       },
-       easeInQuint: function (x, t, b, c, d) {
-               return c*(t/=d)*t*t*t*t + b;
-       },
-       easeOutQuint: function (x, t, b, c, d) {
-               return c*((t=t/d-1)*t*t*t*t + 1) + b;
-       },
-       easeInOutQuint: function (x, t, b, c, d) {
-               if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
-               return c/2*((t-=2)*t*t*t*t + 2) + b;
-       },
-       easeInSine: function (x, t, b, c, d) {
-               return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
-       },
-       easeOutSine: function (x, t, b, c, d) {
-               return c * Math.sin(t/d * (Math.PI/2)) + b;
-       },
-       easeInOutSine: function (x, t, b, c, d) {
-               return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
-       },
-       easeInExpo: function (x, t, b, c, d) {
-               return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
-       },
-       easeOutExpo: function (x, t, b, c, d) {
-               return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
-       },
-       easeInOutExpo: function (x, t, b, c, d) {
-               if (t==0) return b;
-               if (t==d) return b+c;
-               if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
-               return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
-       },
-       easeInCirc: function (x, t, b, c, d) {
-               return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
-       },
-       easeOutCirc: function (x, t, b, c, d) {
-               return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
-       },
-       easeInOutCirc: function (x, t, b, c, d) {
-               if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
-               return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
-       },
-       easeInElastic: function (x, t, b, c, d) {
-               var s=1.70158;var p=0;var a=c;
-               if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
-               if (a < Math.abs(c)) { a=c; var s=p/4; }
-               else var s = p/(2*Math.PI) * Math.asin (c/a);
-               return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
-       },
-       easeOutElastic: function (x, t, b, c, d) {
-               var s=1.70158;var p=0;var a=c;
-               if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
-               if (a < Math.abs(c)) { a=c; var s=p/4; }
-               else var s = p/(2*Math.PI) * Math.asin (c/a);
-               return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
-       },
-       easeInOutElastic: function (x, t, b, c, d) {
-               var s=1.70158;var p=0;var a=c;
-               if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
-               if (a < Math.abs(c)) { a=c; var s=p/4; }
-               else var s = p/(2*Math.PI) * Math.asin (c/a);
-               if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
-               return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
-       },
-       easeInBack: function (x, t, b, c, d, s) {
-               if (s == undefined) s = 1.70158;
-               return c*(t/=d)*t*((s+1)*t - s) + b;
-       },
-       easeOutBack: function (x, t, b, c, d, s) {
-               if (s == undefined) s = 1.70158;
-               return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
-       },
-       easeInOutBack: function (x, t, b, c, d, s) {
-               if (s == undefined) s = 1.70158;
-               if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
-               return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
-       },
-       easeInBounce: function (x, t, b, c, d) {
-               return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
-       },
-       easeOutBounce: function (x, t, b, c, d) {
-               if ((t/=d) < (1/2.75)) {
-                       return c*(7.5625*t*t) + b;
-               } else if (t < (2/2.75)) {
-                       return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
-               } else if (t < (2.5/2.75)) {
-                       return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
-               } else {
-                       return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
-               }
-       },
-       easeInOutBounce: function (x, t, b, c, d) {
-               if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
-               return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
-       }
-});
-
-/*
- *
- * TERMS OF USE - EASING EQUATIONS
- *
- * Open source under the BSD License.
- *
- * Copyright © 2001 Robert Penner
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * Neither the name of the author nor the names of contributors may be used to endorse
- * or promote products derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */;// Custom Easing
-jQuery.extend( jQuery.easing,
-{
-  easeInOutMaterial: function (x, t, b, c, d) {
-    if ((t/=d/2) < 1) return c/2*t*t + b;
-    return c/4*((t-=2)*t*t + 2) + b;
-  }
-});;/*! VelocityJS.org (1.2.3). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */
-/*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */
-/*! Note that this has been modified by Materialize to confirm that Velocity is not already being imported. */
-jQuery.Velocity?console.log("Velocity is already loaded. You may be needlessly importing Velocity again; note that Materialize includes Velocity."):(!function(e){function t(e){var t=e.length,a=r.type(e);return"function"===a||r.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===a||0===t||"number"==typeof t&&t>0&&t-1 in e}if(!e.jQuery){var r=function(e,t){return new r.fn.init(e,t)};r.isWindow=function(e){return null!=e&&e==e.window},r.type=function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e},r.isArray=Array.isArray||function(e){return"array"===r.type(e)},r.isPlainObject=function(e){var t;if(!e||"object"!==r.type(e)||e.nodeType||r.isWindow(e))return!1;try{if(e.constructor&&!o.call(e,"constructor")&&!o.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(a){return!1}for(t in e);return void 0===t||o.call(e,t)},r.each=function(e,r,a){var n,o=0,i=e.length,s=t(e);if(a){if(s)for(;i>o&&(n=r.apply(e[o],a),n!==!1);o++);else for(o in e)if(n=r.apply(e[o],a),n===!1)break}else if(s)for(;i>o&&(n=r.call(e[o],o,e[o]),n!==!1);o++);else for(o in e)if(n=r.call(e[o],o,e[o]),n===!1)break;return e},r.data=function(e,t,n){if(void 0===n){var o=e[r.expando],i=o&&a[o];if(void 0===t)return i;if(i&&t in i)return i[t]}else if(void 0!==t){var o=e[r.expando]||(e[r.expando]=++r.uuid);return a[o]=a[o]||{},a[o][t]=n,n}},r.removeData=function(e,t){var n=e[r.expando],o=n&&a[n];o&&r.each(t,function(e,t){delete o[t]})},r.extend=function(){var e,t,a,n,o,i,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[l]||{},l++),"object"!=typeof s&&"function"!==r.type(s)&&(s={}),l===u&&(s=this,l--);u>l;l++)if(null!=(o=arguments[l]))for(n in o)e=s[n],a=o[n],s!==a&&(c&&a&&(r.isPlainObject(a)||(t=r.isArray(a)))?(t?(t=!1,i=e&&r.isArray(e)?e:[]):i=e&&r.isPlainObject(e)?e:{},s[n]=r.extend(c,i,a)):void 0!==a&&(s[n]=a));return s},r.queue=function(e,a,n){function o(e,r){var a=r||[];return null!=e&&(t(Object(e))?!function(e,t){for(var r=+t.length,a=0,n=e.length;r>a;)e[n++]=t[a++];if(r!==r)for(;void 0!==t[a];)e[n++]=t[a++];return e.length=n,e}(a,"string"==typeof e?[e]:e):[].push.call(a,e)),a}if(e){a=(a||"fx")+"queue";var i=r.data(e,a);return n?(!i||r.isArray(n)?i=r.data(e,a,o(n)):i.push(n),i):i||[]}},r.dequeue=function(e,t){r.each(e.nodeType?[e]:e,function(e,a){t=t||"fx";var n=r.queue(a,t),o=n.shift();"inprogress"===o&&(o=n.shift()),o&&("fx"===t&&n.unshift("inprogress"),o.call(a,function(){r.dequeue(a,t)}))})},r.fn=r.prototype={init:function(e){if(e.nodeType)return this[0]=e,this;throw new Error("Not a DOM node.")},offset:function(){var t=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:t.top+(e.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:t.left+(e.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function e(){for(var e=this.offsetParent||document;e&&"html"===!e.nodeType.toLowerCase&&"static"===e.style.position;)e=e.offsetParent;return e||document}var t=this[0],e=e.apply(t),a=this.offset(),n=/^(?:body|html)$/i.test(e.nodeName)?{top:0,left:0}:r(e).offset();return a.top-=parseFloat(t.style.marginTop)||0,a.left-=parseFloat(t.style.marginLeft)||0,e.style&&(n.top+=parseFloat(e.style.borderTopWidth)||0,n.left+=parseFloat(e.style.borderLeftWidth)||0),{top:a.top-n.top,left:a.left-n.left}}};var a={};r.expando="velocity"+(new Date).getTime(),r.uuid=0;for(var n={},o=n.hasOwnProperty,i=n.toString,s="Boolean Number String Function Array Date RegExp Object Error".split(" "),l=0;l<s.length;l++)n["[object "+s[l]+"]"]=s[l].toLowerCase();r.fn.init.prototype=r.fn,e.Velocity={Utilities:r}}}(window),function(e){"object"==typeof module&&"object"==typeof module.exports?module.exports=e():"function"==typeof define&&define.amd?define(e):e()}(function(){return function(e,t,r,a){function n(e){for(var t=-1,r=e?e.length:0,a=[];++t<r;){var n=e[t];n&&a.push(n)}return a}function o(e){return m.isWrapped(e)?e=[].slice.call(e):m.isNode(e)&&(e=[e]),e}function i(e){var t=f.data(e,"velocity");return null===t?a:t}function s(e){return function(t){return Math.round(t*e)*(1/e)}}function l(e,r,a,n){function o(e,t){return 1-3*t+3*e}function i(e,t){return 3*t-6*e}function s(e){return 3*e}function l(e,t,r){return((o(t,r)*e+i(t,r))*e+s(t))*e}function u(e,t,r){return 3*o(t,r)*e*e+2*i(t,r)*e+s(t)}function c(t,r){for(var n=0;m>n;++n){var o=u(r,e,a);if(0===o)return r;var i=l(r,e,a)-t;r-=i/o}return r}function p(){for(var t=0;b>t;++t)w[t]=l(t*x,e,a)}function f(t,r,n){var o,i,s=0;do i=r+(n-r)/2,o=l(i,e,a)-t,o>0?n=i:r=i;while(Math.abs(o)>h&&++s<v);return i}function d(t){for(var r=0,n=1,o=b-1;n!=o&&w[n]<=t;++n)r+=x;--n;var i=(t-w[n])/(w[n+1]-w[n]),s=r+i*x,l=u(s,e,a);return l>=y?c(t,s):0==l?s:f(t,r,r+x)}function g(){V=!0,(e!=r||a!=n)&&p()}var m=4,y=.001,h=1e-7,v=10,b=11,x=1/(b-1),S="Float32Array"in t;if(4!==arguments.length)return!1;for(var P=0;4>P;++P)if("number"!=typeof arguments[P]||isNaN(arguments[P])||!isFinite(arguments[P]))return!1;e=Math.min(e,1),a=Math.min(a,1),e=Math.max(e,0),a=Math.max(a,0);var w=S?new Float32Array(b):new Array(b),V=!1,C=function(t){return V||g(),e===r&&a===n?t:0===t?0:1===t?1:l(d(t),r,n)};C.getControlPoints=function(){return[{x:e,y:r},{x:a,y:n}]};var T="generateBezier("+[e,r,a,n]+")";return C.toString=function(){return T},C}function u(e,t){var r=e;return m.isString(e)?b.Easings[e]||(r=!1):r=m.isArray(e)&&1===e.length?s.apply(null,e):m.isArray(e)&&2===e.length?x.apply(null,e.concat([t])):m.isArray(e)&&4===e.length?l.apply(null,e):!1,r===!1&&(r=b.Easings[b.defaults.easing]?b.defaults.easing:v),r}function c(e){if(e){var t=(new Date).getTime(),r=b.State.calls.length;r>1e4&&(b.State.calls=n(b.State.calls));for(var o=0;r>o;o++)if(b.State.calls[o]){var s=b.State.calls[o],l=s[0],u=s[2],d=s[3],g=!!d,y=null;d||(d=b.State.calls[o][3]=t-16);for(var h=Math.min((t-d)/u.duration,1),v=0,x=l.length;x>v;v++){var P=l[v],V=P.element;if(i(V)){var C=!1;if(u.display!==a&&null!==u.display&&"none"!==u.display){if("flex"===u.display){var T=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];f.each(T,function(e,t){S.setPropertyValue(V,"display",t)})}S.setPropertyValue(V,"display",u.display)}u.visibility!==a&&"hidden"!==u.visibility&&S.setPropertyValue(V,"visibility",u.visibility);for(var k in P)if("element"!==k){var A,F=P[k],j=m.isString(F.easing)?b.Easings[F.easing]:F.easing;if(1===h)A=F.endValue;else{var E=F.endValue-F.startValue;if(A=F.startValue+E*j(h,u,E),!g&&A===F.currentValue)continue}if(F.currentValue=A,"tween"===k)y=A;else{if(S.Hooks.registered[k]){var H=S.Hooks.getRoot(k),N=i(V).rootPropertyValueCache[H];N&&(F.rootPropertyValue=N)}var L=S.setPropertyValue(V,k,F.currentValue+(0===parseFloat(A)?"":F.unitType),F.rootPropertyValue,F.scrollData);S.Hooks.registered[k]&&(i(V).rootPropertyValueCache[H]=S.Normalizations.registered[H]?S.Normalizations.registered[H]("extract",null,L[1]):L[1]),"transform"===L[0]&&(C=!0)}}u.mobileHA&&i(V).transformCache.translate3d===a&&(i(V).transformCache.translate3d="(0px, 0px, 0px)",C=!0),C&&S.flushTransformCache(V)}}u.display!==a&&"none"!==u.display&&(b.State.calls[o][2].display=!1),u.visibility!==a&&"hidden"!==u.visibility&&(b.State.calls[o][2].visibility=!1),u.progress&&u.progress.call(s[1],s[1],h,Math.max(0,d+u.duration-t),d,y),1===h&&p(o)}}b.State.isTicking&&w(c)}function p(e,t){if(!b.State.calls[e])return!1;for(var r=b.State.calls[e][0],n=b.State.calls[e][1],o=b.State.calls[e][2],s=b.State.calls[e][4],l=!1,u=0,c=r.length;c>u;u++){var p=r[u].element;if(t||o.loop||("none"===o.display&&S.setPropertyValue(p,"display",o.display),"hidden"===o.visibility&&S.setPropertyValue(p,"visibility",o.visibility)),o.loop!==!0&&(f.queue(p)[1]===a||!/\.velocityQueueEntryFlag/i.test(f.queue(p)[1]))&&i(p)){i(p).isAnimating=!1,i(p).rootPropertyValueCache={};var d=!1;f.each(S.Lists.transforms3D,function(e,t){var r=/^scale/.test(t)?1:0,n=i(p).transformCache[t];i(p).transformCache[t]!==a&&new RegExp("^\\("+r+"[^.]").test(n)&&(d=!0,delete i(p).transformCache[t])}),o.mobileHA&&(d=!0,delete i(p).transformCache.translate3d),d&&S.flushTransformCache(p),S.Values.removeClass(p,"velocity-animating")}if(!t&&o.complete&&!o.loop&&u===c-1)try{o.complete.call(n,n)}catch(g){setTimeout(function(){throw g},1)}s&&o.loop!==!0&&s(n),i(p)&&o.loop===!0&&!t&&(f.each(i(p).tweensContainer,function(e,t){/^rotate/.test(e)&&360===parseFloat(t.endValue)&&(t.endValue=0,t.startValue=360),/^backgroundPosition/.test(e)&&100===parseFloat(t.endValue)&&"%"===t.unitType&&(t.endValue=0,t.startValue=100)}),b(p,"reverse",{loop:!0,delay:o.delay})),o.queue!==!1&&f.dequeue(p,o.queue)}b.State.calls[e]=!1;for(var m=0,y=b.State.calls.length;y>m;m++)if(b.State.calls[m]!==!1){l=!0;break}l===!1&&(b.State.isTicking=!1,delete b.State.calls,b.State.calls=[])}var f,d=function(){if(r.documentMode)return r.documentMode;for(var e=7;e>4;e--){var t=r.createElement("div");if(t.innerHTML="<!--[if IE "+e+"]><span></span><![endif]-->",t.getElementsByTagName("span").length)return t=null,e}return a}(),g=function(){var e=0;return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||function(t){var r,a=(new Date).getTime();return r=Math.max(0,16-(a-e)),e=a+r,setTimeout(function(){t(a+r)},r)}}(),m={isString:function(e){return"string"==typeof e},isArray:Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)},isNode:function(e){return e&&e.nodeType},isNodeList:function(e){return"object"==typeof e&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(e))&&e.length!==a&&(0===e.length||"object"==typeof e[0]&&e[0].nodeType>0)},isWrapped:function(e){return e&&(e.jquery||t.Zepto&&t.Zepto.zepto.isZ(e))},isSVG:function(e){return t.SVGElement&&e instanceof t.SVGElement},isEmptyObject:function(e){for(var t in e)return!1;return!0}},y=!1;if(e.fn&&e.fn.jquery?(f=e,y=!0):f=t.Velocity.Utilities,8>=d&&!y)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=d)return void(jQuery.fn.velocity=jQuery.fn.animate);var h=400,v="swing",b={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:t.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:r.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:f,Redirects:{},Easings:{},Promise:t.Promise,defaults:{queue:"",duration:h,easing:v,begin:a,complete:a,progress:a,display:a,visibility:a,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(e){f.data(e,"velocity",{isSVG:m.isSVG(e),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:2},debug:!1};t.pageYOffset!==a?(b.State.scrollAnchor=t,b.State.scrollPropertyLeft="pageXOffset",b.State.scrollPropertyTop="pageYOffset"):(b.State.scrollAnchor=r.documentElement||r.body.parentNode||r.body,b.State.scrollPropertyLeft="scrollLeft",b.State.scrollPropertyTop="scrollTop");var x=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,a){var n={x:t.x+a.dx*r,v:t.v+a.dv*r,tension:t.tension,friction:t.friction};return{dx:n.v,dv:e(n)}}function r(r,a){var n={dx:r.v,dv:e(r)},o=t(r,.5*a,n),i=t(r,.5*a,o),s=t(r,a,i),l=1/6*(n.dx+2*(o.dx+i.dx)+s.dx),u=1/6*(n.dv+2*(o.dv+i.dv)+s.dv);return r.x=r.x+l*a,r.v=r.v+u*a,r}return function a(e,t,n){var o,i,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0,p=1e-4,f=.016;for(e=parseFloat(e)||500,t=parseFloat(t)||20,n=n||null,l.tension=e,l.friction=t,o=null!==n,o?(c=a(e,t),i=c/n*f):i=f;s=r(s||l,i),u.push(1+s.x),c+=16,Math.abs(s.x)>p&&Math.abs(s.v)>p;);return o?function(e){return u[e*(u.length-1)|0]}:c}}();b.Easings={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},spring:function(e){return 1-Math.cos(4.5*e*Math.PI)*Math.exp(6*-e)}},f.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(e,t){b.Easings[t[0]]=l.apply(null,t[1])});var S=b.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var e=0;e<S.Lists.colors.length;e++){var t="color"===S.Lists.colors[e]?"0 0 0 1":"255 255 255 1";S.Hooks.templates[S.Lists.colors[e]]=["Red Green Blue Alpha",t]}var r,a,n;if(d)for(r in S.Hooks.templates){a=S.Hooks.templates[r],n=a[0].split(" ");var o=a[1].match(S.RegEx.valueSplit);"Color"===n[0]&&(n.push(n.shift()),o.push(o.shift()),S.Hooks.templates[r]=[n.join(" "),o.join(" ")])}for(r in S.Hooks.templates){a=S.Hooks.templates[r],n=a[0].split(" ");for(var e in n){var i=r+n[e],s=e;S.Hooks.registered[i]=[r,s]}}},getRoot:function(e){var t=S.Hooks.registered[e];return t?t[0]:e},cleanRootPropertyValue:function(e,t){return S.RegEx.valueUnwrap.test(t)&&(t=t.match(S.RegEx.valueUnwrap)[1]),S.Values.isCSSNullValue(t)&&(t=S.Hooks.templates[e][1]),t},extractValue:function(e,t){var r=S.Hooks.registered[e];if(r){var a=r[0],n=r[1];return t=S.Hooks.cleanRootPropertyValue(a,t),t.toString().match(S.RegEx.valueSplit)[n]}return t},injectValue:function(e,t,r){var a=S.Hooks.registered[e];if(a){var n,o,i=a[0],s=a[1];return r=S.Hooks.cleanRootPropertyValue(i,r),n=r.toString().match(S.RegEx.valueSplit),n[s]=t,o=n.join(" ")}return r}},Normalizations:{registered:{clip:function(e,t,r){switch(e){case"name":return"clip";case"extract":var a;return S.RegEx.wrappedValueAlreadyExtracted.test(r)?a=r:(a=r.toString().match(S.RegEx.valueUnwrap),a=a?a[1].replace(/,(\s+)?/g," "):r),a;case"inject":return"rect("+r+")"}},blur:function(e,t,r){switch(e){case"name":return b.State.isFirefox?"filter":"-webkit-filter";case"extract":var a=parseFloat(r);if(!a&&0!==a){var n=r.toString().match(/blur\(([0-9]+[A-z]+)\)/i);a=n?n[1]:0}return a;case"inject":return parseFloat(r)?"blur("+r+")":"none"}},opacity:function(e,t,r){if(8>=d)switch(e){case"name":return"filter";case"extract":var a=r.toString().match(/alpha\(opacity=(.*)\)/i);return r=a?a[1]/100:1;case"inject":return t.style.zoom=1,parseFloat(r)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(r),10)+")"}else switch(e){case"name":return"opacity";case"extract":return r;case"inject":return r}}},register:function(){9>=d||b.State.isGingerbread||(S.Lists.transformsBase=S.Lists.transformsBase.concat(S.Lists.transforms3D));for(var e=0;e<S.Lists.transformsBase.length;e++)!function(){var t=S.Lists.transformsBase[e];S.Normalizations.registered[t]=function(e,r,n){switch(e){case"name":return"transform";case"extract":return i(r)===a||i(r).transformCache[t]===a?/^scale/i.test(t)?1:0:i(r).transformCache[t].replace(/[()]/g,"");case"inject":var o=!1;switch(t.substr(0,t.length-1)){case"translate":o=!/(%|px|em|rem|vw|vh|\d)$/i.test(n);break;case"scal":case"scale":b.State.isAndroid&&i(r).transformCache[t]===a&&1>n&&(n=1),o=!/(\d)$/i.test(n);break;case"skew":o=!/(deg|\d)$/i.test(n);break;case"rotate":o=!/(deg|\d)$/i.test(n)}return o||(i(r).transformCache[t]="("+n+")"),i(r).transformCache[t]}}}();for(var e=0;e<S.Lists.colors.length;e++)!function(){var t=S.Lists.colors[e];S.Normalizations.registered[t]=function(e,r,n){switch(e){case"name":return t;case"extract":var o;if(S.RegEx.wrappedValueAlreadyExtracted.test(n))o=n;else{var i,s={black:"rgb(0, 0, 0)",blue:"rgb(0, 0, 255)",gray:"rgb(128, 128, 128)",green:"rgb(0, 128, 0)",red:"rgb(255, 0, 0)",white:"rgb(255, 255, 255)"};/^[A-z]+$/i.test(n)?i=s[n]!==a?s[n]:s.black:S.RegEx.isHex.test(n)?i="rgb("+S.Values.hexToRgb(n).join(" ")+")":/^rgba?\(/i.test(n)||(i=s.black),o=(i||n).toString().match(S.RegEx.valueUnwrap)[1].replace(/,(\s+)?/g," ")}return 8>=d||3!==o.split(" ").length||(o+=" 1"),o;case"inject":return 8>=d?4===n.split(" ").length&&(n=n.split(/\s+/).slice(0,3).join(" ")):3===n.split(" ").length&&(n+=" 1"),(8>=d?"rgb":"rgba")+"("+n.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(e){return e.replace(/-(\w)/g,function(e,t){return t.toUpperCase()})},SVGAttribute:function(e){var t="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(d||b.State.isAndroid&&!b.State.isChrome)&&(t+="|transform"),new RegExp("^("+t+")$","i").test(e)},prefixCheck:function(e){if(b.State.prefixMatches[e])return[b.State.prefixMatches[e],!0];for(var t=["","Webkit","Moz","ms","O"],r=0,a=t.length;a>r;r++){var n;if(n=0===r?e:t[r]+e.replace(/^\w/,function(e){return e.toUpperCase()}),m.isString(b.State.prefixElement.style[n]))return b.State.prefixMatches[e]=n,[n,!0]}return[e,!1]}},Values:{hexToRgb:function(e){var t,r=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;return e=e.replace(r,function(e,t,r,a){return t+t+r+r+a+a}),t=a.exec(e),t?[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]:[0,0,0]},isCSSNullValue:function(e){return 0==e||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(e)},getUnitType:function(e){return/^(rotate|skew)/i.test(e)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(e)?"":"px"},getDisplayType:function(e){var t=e&&e.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(t)?"inline":/^(li)$/i.test(t)?"list-item":/^(tr)$/i.test(t)?"table-row":/^(table)$/i.test(t)?"table":/^(tbody)$/i.test(t)?"table-row-group":"block"},addClass:function(e,t){e.classList?e.classList.add(t):e.className+=(e.className.length?" ":"")+t},removeClass:function(e,t){e.classList?e.classList.remove(t):e.className=e.className.toString().replace(new RegExp("(^|\\s)"+t.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(e,r,n,o){function s(e,r){function n(){u&&S.setPropertyValue(e,"display","none")}var l=0;if(8>=d)l=f.css(e,r);else{var u=!1;if(/^(width|height)$/.test(r)&&0===S.getPropertyValue(e,"display")&&(u=!0,S.setPropertyValue(e,"display",S.Values.getDisplayType(e))),!o){if("height"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var c=e.offsetHeight-(parseFloat(S.getPropertyValue(e,"borderTopWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderBottomWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingTop"))||0)-(parseFloat(S.getPropertyValue(e,"paddingBottom"))||0);return n(),c}if("width"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var p=e.offsetWidth-(parseFloat(S.getPropertyValue(e,"borderLeftWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderRightWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingLeft"))||0)-(parseFloat(S.getPropertyValue(e,"paddingRight"))||0);return n(),p}}var g;g=i(e)===a?t.getComputedStyle(e,null):i(e).computedStyle?i(e).computedStyle:i(e).computedStyle=t.getComputedStyle(e,null),"borderColor"===r&&(r="borderTopColor"),l=9===d&&"filter"===r?g.getPropertyValue(r):g[r],(""===l||null===l)&&(l=e.style[r]),n()}if("auto"===l&&/^(top|right|bottom|left)$/i.test(r)){var m=s(e,"position");("fixed"===m||"absolute"===m&&/top|left/i.test(r))&&(l=f(e).position()[r]+"px")}return l}var l;if(S.Hooks.registered[r]){var u=r,c=S.Hooks.getRoot(u);n===a&&(n=S.getPropertyValue(e,S.Names.prefixCheck(c)[0])),S.Normalizations.registered[c]&&(n=S.Normalizations.registered[c]("extract",e,n)),l=S.Hooks.extractValue(u,n)}else if(S.Normalizations.registered[r]){var p,g;p=S.Normalizations.registered[r]("name",e),"transform"!==p&&(g=s(e,S.Names.prefixCheck(p)[0]),S.Values.isCSSNullValue(g)&&S.Hooks.templates[r]&&(g=S.Hooks.templates[r][1])),l=S.Normalizations.registered[r]("extract",e,g)}if(!/^[\d-]/.test(l))if(i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r))if(/^(height|width)$/i.test(r))try{l=e.getBBox()[r]}catch(m){l=0}else l=e.getAttribute(r);else l=s(e,S.Names.prefixCheck(r)[0]);return S.Values.isCSSNullValue(l)&&(l=0),b.debug>=2&&console.log("Get "+r+": "+l),l},setPropertyValue:function(e,r,a,n,o){var s=r;if("scroll"===r)o.container?o.container["scroll"+o.direction]=a:"Left"===o.direction?t.scrollTo(a,o.alternateValue):t.scrollTo(o.alternateValue,a);else if(S.Normalizations.registered[r]&&"transform"===S.Normalizations.registered[r]("name",e))S.Normalizations.registered[r]("inject",e,a),s="transform",a=i(e).transformCache[r];else{if(S.Hooks.registered[r]){var l=r,u=S.Hooks.getRoot(r);n=n||S.getPropertyValue(e,u),a=S.Hooks.injectValue(l,a,n),r=u}if(S.Normalizations.registered[r]&&(a=S.Normalizations.registered[r]("inject",e,a),r=S.Normalizations.registered[r]("name",e)),s=S.Names.prefixCheck(r)[0],8>=d)try{e.style[s]=a}catch(c){b.debug&&console.log("Browser does not support ["+a+"] for ["+s+"]")}else i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r)?e.setAttribute(r,a):e.style[s]=a;b.debug>=2&&console.log("Set "+r+" ("+s+"): "+a)}return[s,a]},flushTransformCache:function(e){function t(t){return parseFloat(S.getPropertyValue(e,t))}var r="";if((d||b.State.isAndroid&&!b.State.isChrome)&&i(e).isSVG){var a={translate:[t("translateX"),t("translateY")],skewX:[t("skewX")],skewY:[t("skewY")],scale:1!==t("scale")?[t("scale"),t("scale")]:[t("scaleX"),t("scaleY")],rotate:[t("rotateZ"),0,0]};f.each(i(e).transformCache,function(e){/^translate/i.test(e)?e="translate":/^scale/i.test(e)?e="scale":/^rotate/i.test(e)&&(e="rotate"),a[e]&&(r+=e+"("+a[e].join(" ")+") ",delete a[e])})}else{var n,o;f.each(i(e).transformCache,function(t){return n=i(e).transformCache[t],"transformPerspective"===t?(o=n,!0):(9===d&&"rotateZ"===t&&(t="rotate"),void(r+=t+n+" "))}),o&&(r="perspective"+o+" "+r)}S.setPropertyValue(e,"transform",r)}};S.Hooks.register(),S.Normalizations.register(),b.hook=function(e,t,r){var n=a;return e=o(e),f.each(e,function(e,o){if(i(o)===a&&b.init(o),r===a)n===a&&(n=b.CSS.getPropertyValue(o,t));else{var s=b.CSS.setPropertyValue(o,t,r);"transform"===s[0]&&b.CSS.flushTransformCache(o),n=s}}),n};var P=function(){function e(){return s?k.promise||null:l}function n(){function e(e){function p(e,t){var r=a,n=a,i=a;return m.isArray(e)?(r=e[0],!m.isArray(e[1])&&/^[\d-]/.test(e[1])||m.isFunction(e[1])||S.RegEx.isHex.test(e[1])?i=e[1]:(m.isString(e[1])&&!S.RegEx.isHex.test(e[1])||m.isArray(e[1]))&&(n=t?e[1]:u(e[1],s.duration),e[2]!==a&&(i=e[2]))):r=e,t||(n=n||s.easing),m.isFunction(r)&&(r=r.call(o,V,w)),m.isFunction(i)&&(i=i.call(o,V,w)),[r||0,n,i]}function d(e,t){var r,a;return a=(t||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(e){return r=e,""}),r||(r=S.Values.getUnitType(e)),[a,r]}function h(){var e={myParent:o.parentNode||r.body,position:S.getPropertyValue(o,"position"),fontSize:S.getPropertyValue(o,"fontSize")},a=e.position===L.lastPosition&&e.myParent===L.lastParent,n=e.fontSize===L.lastFontSize;L.lastParent=e.myParent,L.lastPosition=e.position,L.lastFontSize=e.fontSize;var s=100,l={};if(n&&a)l.emToPx=L.lastEmToPx,l.percentToPxWidth=L.lastPercentToPxWidth,l.percentToPxHeight=L.lastPercentToPxHeight;else{var u=i(o).isSVG?r.createElementNS("http://www.w3.org/2000/svg","rect"):r.createElement("div");b.init(u),e.myParent.appendChild(u),f.each(["overflow","overflowX","overflowY"],function(e,t){b.CSS.setPropertyValue(u,t,"hidden")}),b.CSS.setPropertyValue(u,"position",e.position),b.CSS.setPropertyValue(u,"fontSize",e.fontSize),b.CSS.setPropertyValue(u,"boxSizing","content-box"),f.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(e,t){b.CSS.setPropertyValue(u,t,s+"%")}),b.CSS.setPropertyValue(u,"paddingLeft",s+"em"),l.percentToPxWidth=L.lastPercentToPxWidth=(parseFloat(S.getPropertyValue(u,"width",null,!0))||1)/s,l.percentToPxHeight=L.lastPercentToPxHeight=(parseFloat(S.getPropertyValue(u,"height",null,!0))||1)/s,l.emToPx=L.lastEmToPx=(parseFloat(S.getPropertyValue(u,"paddingLeft"))||1)/s,e.myParent.removeChild(u)}return null===L.remToPx&&(L.remToPx=parseFloat(S.getPropertyValue(r.body,"fontSize"))||16),null===L.vwToPx&&(L.vwToPx=parseFloat(t.innerWidth)/100,L.vhToPx=parseFloat(t.innerHeight)/100),l.remToPx=L.remToPx,l.vwToPx=L.vwToPx,l.vhToPx=L.vhToPx,b.debug>=1&&console.log("Unit ratios: "+JSON.stringify(l),o),l}if(s.begin&&0===V)try{s.begin.call(g,g)}catch(x){setTimeout(function(){throw x},1)}if("scroll"===A){var P,C,T,F=/^x$/i.test(s.axis)?"Left":"Top",j=parseFloat(s.offset)||0;s.container?m.isWrapped(s.container)||m.isNode(s.container)?(s.container=s.container[0]||s.container,P=s.container["scroll"+F],T=P+f(o).position()[F.toLowerCase()]+j):s.container=null:(P=b.State.scrollAnchor[b.State["scrollProperty"+F]],C=b.State.scrollAnchor[b.State["scrollProperty"+("Left"===F?"Top":"Left")]],T=f(o).offset()[F.toLowerCase()]+j),l={scroll:{rootPropertyValue:!1,startValue:P,currentValue:P,endValue:T,unitType:"",easing:s.easing,scrollData:{container:s.container,direction:F,alternateValue:C}},element:o},b.debug&&console.log("tweensContainer (scroll): ",l.scroll,o)}else if("reverse"===A){if(!i(o).tweensContainer)return void f.dequeue(o,s.queue);"none"===i(o).opts.display&&(i(o).opts.display="auto"),"hidden"===i(o).opts.visibility&&(i(o).opts.visibility="visible"),i(o).opts.loop=!1,i(o).opts.begin=null,i(o).opts.complete=null,v.easing||delete s.easing,v.duration||delete s.duration,s=f.extend({},i(o).opts,s);var E=f.extend(!0,{},i(o).tweensContainer);for(var H in E)if("element"!==H){var N=E[H].startValue;E[H].startValue=E[H].currentValue=E[H].endValue,E[H].endValue=N,m.isEmptyObject(v)||(E[H].easing=s.easing),b.debug&&console.log("reverse tweensContainer ("+H+"): "+JSON.stringify(E[H]),o)}l=E}else if("start"===A){var E;i(o).tweensContainer&&i(o).isAnimating===!0&&(E=i(o).tweensContainer),f.each(y,function(e,t){if(RegExp("^"+S.Lists.colors.join("$|^")+"$").test(e)){var r=p(t,!0),n=r[0],o=r[1],i=r[2];if(S.RegEx.isHex.test(n)){for(var s=["Red","Green","Blue"],l=S.Values.hexToRgb(n),u=i?S.Values.hexToRgb(i):a,c=0;c<s.length;c++){var f=[l[c]];o&&f.push(o),u!==a&&f.push(u[c]),y[e+s[c]]=f}delete y[e]}}});for(var z in y){var O=p(y[z]),q=O[0],$=O[1],M=O[2];z=S.Names.camelCase(z);var I=S.Hooks.getRoot(z),B=!1;if(i(o).isSVG||"tween"===I||S.Names.prefixCheck(I)[1]!==!1||S.Normalizations.registered[I]!==a){(s.display!==a&&null!==s.display&&"none"!==s.display||s.visibility!==a&&"hidden"!==s.visibility)&&/opacity|filter/.test(z)&&!M&&0!==q&&(M=0),s._cacheValues&&E&&E[z]?(M===a&&(M=E[z].endValue+E[z].unitType),B=i(o).rootPropertyValueCache[I]):S.Hooks.registered[z]?M===a?(B=S.getPropertyValue(o,I),M=S.getPropertyValue(o,z,B)):B=S.Hooks.templates[I][1]:M===a&&(M=S.getPropertyValue(o,z));var W,G,Y,D=!1;if(W=d(z,M),M=W[0],Y=W[1],W=d(z,q),q=W[0].replace(/^([+-\/*])=/,function(e,t){return D=t,""}),G=W[1],M=parseFloat(M)||0,q=parseFloat(q)||0,"%"===G&&(/^(fontSize|lineHeight)$/.test(z)?(q/=100,G="em"):/^scale/.test(z)?(q/=100,G=""):/(Red|Green|Blue)$/i.test(z)&&(q=q/100*255,G="")),/[\/*]/.test(D))G=Y;else if(Y!==G&&0!==M)if(0===q)G=Y;else{n=n||h();var Q=/margin|padding|left|right|width|text|word|letter/i.test(z)||/X$/.test(z)||"x"===z?"x":"y";switch(Y){case"%":M*="x"===Q?n.percentToPxWidth:n.percentToPxHeight;break;case"px":break;default:M*=n[Y+"ToPx"]}switch(G){case"%":M*=1/("x"===Q?n.percentToPxWidth:n.percentToPxHeight);break;case"px":break;default:M*=1/n[G+"ToPx"]}}switch(D){case"+":q=M+q;break;case"-":q=M-q;break;case"*":q=M*q;break;case"/":q=M/q}l[z]={rootPropertyValue:B,startValue:M,currentValue:M,endValue:q,unitType:G,easing:$},b.debug&&console.log("tweensContainer ("+z+"): "+JSON.stringify(l[z]),o)}else b.debug&&console.log("Skipping ["+I+"] due to a lack of browser support.")}l.element=o}l.element&&(S.Values.addClass(o,"velocity-animating"),R.push(l),""===s.queue&&(i(o).tweensContainer=l,i(o).opts=s),i(o).isAnimating=!0,V===w-1?(b.State.calls.push([R,g,s,null,k.resolver]),b.State.isTicking===!1&&(b.State.isTicking=!0,c())):V++)}var n,o=this,s=f.extend({},b.defaults,v),l={};switch(i(o)===a&&b.init(o),parseFloat(s.delay)&&s.queue!==!1&&f.queue(o,s.queue,function(e){b.velocityQueueEntryFlag=!0,i(o).delayTimer={setTimeout:setTimeout(e,parseFloat(s.delay)),next:e}}),s.duration.toString().toLowerCase()){case"fast":s.duration=200;break;case"normal":s.duration=h;break;case"slow":s.duration=600;break;default:s.duration=parseFloat(s.duration)||1}b.mock!==!1&&(b.mock===!0?s.duration=s.delay=1:(s.duration*=parseFloat(b.mock)||1,s.delay*=parseFloat(b.mock)||1)),s.easing=u(s.easing,s.duration),s.begin&&!m.isFunction(s.begin)&&(s.begin=null),s.progress&&!m.isFunction(s.progress)&&(s.progress=null),s.complete&&!m.isFunction(s.complete)&&(s.complete=null),s.display!==a&&null!==s.display&&(s.display=s.display.toString().toLowerCase(),"auto"===s.display&&(s.display=b.CSS.Values.getDisplayType(o))),s.visibility!==a&&null!==s.visibility&&(s.visibility=s.visibility.toString().toLowerCase()),s.mobileHA=s.mobileHA&&b.State.isMobile&&!b.State.isGingerbread,s.queue===!1?s.delay?setTimeout(e,s.delay):e():f.queue(o,s.queue,function(t,r){return r===!0?(k.promise&&k.resolver(g),!0):(b.velocityQueueEntryFlag=!0,void e(t))}),""!==s.queue&&"fx"!==s.queue||"inprogress"===f.queue(o)[0]||f.dequeue(o)}var s,l,d,g,y,v,x=arguments[0]&&(arguments[0].p||f.isPlainObject(arguments[0].properties)&&!arguments[0].properties.names||m.isString(arguments[0].properties));if(m.isWrapped(this)?(s=!1,d=0,g=this,l=this):(s=!0,d=1,g=x?arguments[0].elements||arguments[0].e:arguments[0]),g=o(g)){x?(y=arguments[0].properties||arguments[0].p,v=arguments[0].options||arguments[0].o):(y=arguments[d],v=arguments[d+1]);var w=g.length,V=0;if(!/^(stop|finish)$/i.test(y)&&!f.isPlainObject(v)){var C=d+1;v={};for(var T=C;T<arguments.length;T++)m.isArray(arguments[T])||!/^(fast|normal|slow)$/i.test(arguments[T])&&!/^\d/.test(arguments[T])?m.isString(arguments[T])||m.isArray(arguments[T])?v.easing=arguments[T]:m.isFunction(arguments[T])&&(v.complete=arguments[T]):v.duration=arguments[T]}var k={promise:null,resolver:null,rejecter:null};s&&b.Promise&&(k.promise=new b.Promise(function(e,t){k.resolver=e,k.rejecter=t}));var A;switch(y){case"scroll":A="scroll";break;case"reverse":A="reverse";break;case"finish":case"stop":f.each(g,function(e,t){i(t)&&i(t).delayTimer&&(clearTimeout(i(t).delayTimer.setTimeout),i(t).delayTimer.next&&i(t).delayTimer.next(),delete i(t).delayTimer)});var F=[];return f.each(b.State.calls,function(e,t){t&&f.each(t[1],function(r,n){var o=v===a?"":v;return o===!0||t[2].queue===o||v===a&&t[2].queue===!1?void f.each(g,function(r,a){a===n&&((v===!0||m.isString(v))&&(f.each(f.queue(a,m.isString(v)?v:""),function(e,t){
-m.isFunction(t)&&t(null,!0)}),f.queue(a,m.isString(v)?v:"",[])),"stop"===y?(i(a)&&i(a).tweensContainer&&o!==!1&&f.each(i(a).tweensContainer,function(e,t){t.endValue=t.currentValue}),F.push(e)):"finish"===y&&(t[2].duration=1))}):!0})}),"stop"===y&&(f.each(F,function(e,t){p(t,!0)}),k.promise&&k.resolver(g)),e();default:if(!f.isPlainObject(y)||m.isEmptyObject(y)){if(m.isString(y)&&b.Redirects[y]){var j=f.extend({},v),E=j.duration,H=j.delay||0;return j.backwards===!0&&(g=f.extend(!0,[],g).reverse()),f.each(g,function(e,t){parseFloat(j.stagger)?j.delay=H+parseFloat(j.stagger)*e:m.isFunction(j.stagger)&&(j.delay=H+j.stagger.call(t,e,w)),j.drag&&(j.duration=parseFloat(E)||(/^(callout|transition)/.test(y)?1e3:h),j.duration=Math.max(j.duration*(j.backwards?1-e/w:(e+1)/w),.75*j.duration,200)),b.Redirects[y].call(t,t,j||{},e,w,g,k.promise?k:a)}),e()}var N="Velocity: First argument ("+y+") was not a property map, a known action, or a registered redirect. Aborting.";return k.promise?k.rejecter(new Error(N)):console.log(N),e()}A="start"}var L={lastParent:null,lastPosition:null,lastFontSize:null,lastPercentToPxWidth:null,lastPercentToPxHeight:null,lastEmToPx:null,remToPx:null,vwToPx:null,vhToPx:null},R=[];f.each(g,function(e,t){m.isNode(t)&&n.call(t)});var z,j=f.extend({},b.defaults,v);if(j.loop=parseInt(j.loop),z=2*j.loop-1,j.loop)for(var O=0;z>O;O++){var q={delay:j.delay,progress:j.progress};O===z-1&&(q.display=j.display,q.visibility=j.visibility,q.complete=j.complete),P(g,"reverse",q)}return e()}};b=f.extend(P,b),b.animate=P;var w=t.requestAnimationFrame||g;return b.State.isMobile||r.hidden===a||r.addEventListener("visibilitychange",function(){r.hidden?(w=function(e){return setTimeout(function(){e(!0)},16)},c()):w=t.requestAnimationFrame||g}),e.Velocity=b,e!==t&&(e.fn.velocity=P,e.fn.velocity.defaults=b.defaults),f.each(["Down","Up"],function(e,t){b.Redirects["slide"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u=l.begin,c=l.complete,p={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},d={};l.display===a&&(l.display="Down"===t?"inline"===b.CSS.Values.getDisplayType(e)?"inline-block":"block":"none"),l.begin=function(){u&&u.call(i,i);for(var r in p){d[r]=e.style[r];var a=b.CSS.getPropertyValue(e,r);p[r]="Down"===t?[a,0]:[0,a]}d.overflow=e.style.overflow,e.style.overflow="hidden"},l.complete=function(){for(var t in d)e.style[t]=d[t];c&&c.call(i,i),s&&s.resolver(i)},b(e,p,l)}}),f.each(["In","Out"],function(e,t){b.Redirects["fade"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u={opacity:"In"===t?1:0},c=l.complete;l.complete=n!==o-1?l.begin=null:function(){c&&c.call(i,i),s&&s.resolver(i)},l.display===a&&(l.display="In"===t?"auto":"none"),b(this,u,l)}}),b}(window.jQuery||window.Zepto||window,window,document)}));
-;!function(a,b,c,d){"use strict";function k(a,b,c){return setTimeout(q(a,c),b)}function l(a,b,c){return Array.isArray(a)?(m(a,c[b],c),!0):!1}function m(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e<a.length;)b.call(c,a[e],e,a),e++;else for(e in a)a.hasOwnProperty(e)&&b.call(c,a[e],e,a)}function n(a,b,c){for(var e=Object.keys(b),f=0;f<e.length;)(!c||c&&a[e[f]]===d)&&(a[e[f]]=b[e[f]]),f++;return a}function o(a,b){return n(a,b,!0)}function p(a,b,c){var e,d=b.prototype;e=a.prototype=Object.create(d),e.constructor=a,e._super=d,c&&n(e,c)}function q(a,b){return function(){return a.apply(b,arguments)}}function r(a,b){return typeof a==g?a.apply(b?b[0]||d:d,b):a}function s(a,b){return a===d?b:a}function t(a,b,c){m(x(b),function(b){a.addEventListener(b,c,!1)})}function u(a,b,c){m(x(b),function(b){a.removeEventListener(b,c,!1)})}function v(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function w(a,b){return a.indexOf(b)>-1}function x(a){return a.trim().split(/\s+/g)}function y(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;d<a.length;){if(c&&a[d][c]==b||!c&&a[d]===b)return d;d++}return-1}function z(a){return Array.prototype.slice.call(a,0)}function A(a,b,c){for(var d=[],e=[],f=0;f<a.length;){var g=b?a[f][b]:a[f];y(e,g)<0&&d.push(a[f]),e[f]=g,f++}return c&&(d=b?d.sort(function(a,c){return a[b]>c[b]}):d.sort()),d}function B(a,b){for(var c,f,g=b[0].toUpperCase()+b.slice(1),h=0;h<e.length;){if(c=e[h],f=c?c+g:b,f in a)return f;h++}return d}function D(){return C++}function E(a){var b=a.ownerDocument;return b.defaultView||b.parentWindow}function ab(a,b){var c=this;this.manager=a,this.callback=b,this.element=a.element,this.target=a.options.inputTarget,this.domHandler=function(b){r(a.options.enable,[a])&&c.handler(b)},this.init()}function bb(a){var b,c=a.options.inputClass;return b=c?c:H?wb:I?Eb:G?Gb:rb,new b(a,cb)}function cb(a,b,c){var d=c.pointers.length,e=c.changedPointers.length,f=b&O&&0===d-e,g=b&(Q|R)&&0===d-e;c.isFirst=!!f,c.isFinal=!!g,f&&(a.session={}),c.eventType=b,db(a,c),a.emit("hammer.input",c),a.recognize(c),a.session.prevInput=c}function db(a,b){var c=a.session,d=b.pointers,e=d.length;c.firstInput||(c.firstInput=gb(b)),e>1&&!c.firstMultiple?c.firstMultiple=gb(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=hb(d);b.timeStamp=j(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=lb(h,i),b.distance=kb(h,i),eb(c,b),b.offsetDirection=jb(b.deltaX,b.deltaY),b.scale=g?nb(g.pointers,d):1,b.rotation=g?mb(g.pointers,d):0,fb(c,b);var k=a.element;v(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function eb(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};(b.eventType===O||f.eventType===Q)&&(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function fb(a,b){var f,g,h,j,c=a.lastInterval||b,e=b.timeStamp-c.timeStamp;if(b.eventType!=R&&(e>N||c.velocity===d)){var k=c.deltaX-b.deltaX,l=c.deltaY-b.deltaY,m=ib(e,k,l);g=m.x,h=m.y,f=i(m.x)>i(m.y)?m.x:m.y,j=jb(k,l),a.lastInterval=b}else f=c.velocity,g=c.velocityX,h=c.velocityY,j=c.direction;b.velocity=f,b.velocityX=g,b.velocityY=h,b.direction=j}function gb(a){for(var b=[],c=0;c<a.pointers.length;)b[c]={clientX:h(a.pointers[c].clientX),clientY:h(a.pointers[c].clientY)},c++;return{timeStamp:j(),pointers:b,center:hb(b),deltaX:a.deltaX,deltaY:a.deltaY}}function hb(a){var b=a.length;if(1===b)return{x:h(a[0].clientX),y:h(a[0].clientY)};for(var c=0,d=0,e=0;b>e;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:h(c/b),y:h(d/b)}}function ib(a,b,c){return{x:b/a||0,y:c/a||0}}function jb(a,b){return a===b?S:i(a)>=i(b)?a>0?T:U:b>0?V:W}function kb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function lb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function mb(a,b){return lb(b[1],b[0],_)-lb(a[1],a[0],_)}function nb(a,b){return kb(b[0],b[1],_)/kb(a[0],a[1],_)}function rb(){this.evEl=pb,this.evWin=qb,this.allow=!0,this.pressed=!1,ab.apply(this,arguments)}function wb(){this.evEl=ub,this.evWin=vb,ab.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function Ab(){this.evTarget=yb,this.evWin=zb,this.started=!1,ab.apply(this,arguments)}function Bb(a,b){var c=z(a.touches),d=z(a.changedTouches);return b&(Q|R)&&(c=A(c.concat(d),"identifier",!0)),[c,d]}function Eb(){this.evTarget=Db,this.targetIds={},ab.apply(this,arguments)}function Fb(a,b){var c=z(a.touches),d=this.targetIds;if(b&(O|P)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=z(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return v(a.target,i)}),b===O)for(e=0;e<f.length;)d[f[e].identifier]=!0,e++;for(e=0;e<g.length;)d[g[e].identifier]&&h.push(g[e]),b&(Q|R)&&delete d[g[e].identifier],e++;return h.length?[A(f.concat(h),"identifier",!0),h]:void 0}function Gb(){ab.apply(this,arguments);var a=q(this.handler,this);this.touch=new Eb(this.manager,a),this.mouse=new rb(this.manager,a)}function Pb(a,b){this.manager=a,this.set(b)}function Qb(a){if(w(a,Mb))return Mb;var b=w(a,Nb),c=w(a,Ob);return b&&c?Nb+" "+Ob:b||c?b?Nb:Ob:w(a,Lb)?Lb:Kb}function Yb(a){this.id=D(),this.manager=null,this.options=o(a||{},this.defaults),this.options.enable=s(this.options.enable,!0),this.state=Rb,this.simultaneous={},this.requireFail=[]}function Zb(a){return a&Wb?"cancel":a&Ub?"end":a&Tb?"move":a&Sb?"start":""}function $b(a){return a==W?"down":a==V?"up":a==T?"left":a==U?"right":""}function _b(a,b){var c=b.manager;return c?c.get(a):a}function ac(){Yb.apply(this,arguments)}function bc(){ac.apply(this,arguments),this.pX=null,this.pY=null}function cc(){ac.apply(this,arguments)}function dc(){Yb.apply(this,arguments),this._timer=null,this._input=null}function ec(){ac.apply(this,arguments)}function fc(){ac.apply(this,arguments)}function gc(){Yb.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function hc(a,b){return b=b||{},b.recognizers=s(b.recognizers,hc.defaults.preset),new kc(a,b)}function kc(a,b){b=b||{},this.options=o(b,hc.defaults),this.options.inputTarget=this.options.inputTarget||a,this.handlers={},this.session={},this.recognizers=[],this.element=a,this.input=bb(this),this.touchAction=new Pb(this,this.options.touchAction),lc(this,!0),m(b.recognizers,function(a){var b=this.add(new a[0](a[1]));a[2]&&b.recognizeWith(a[2]),a[3]&&b.requireFailure(a[3])},this)}function lc(a,b){var c=a.element;m(a.options.cssProps,function(a,d){c.style[B(c.style,d)]=b?a:""})}function mc(a,c){var d=b.createEvent("Event");d.initEvent(a,!0,!0),d.gesture=c,c.target.dispatchEvent(d)}var e=["","webkit","moz","MS","ms","o"],f=b.createElement("div"),g="function",h=Math.round,i=Math.abs,j=Date.now,C=1,F=/mobile|tablet|ip(ad|hone|od)|android/i,G="ontouchstart"in a,H=B(a,"PointerEvent")!==d,I=G&&F.test(navigator.userAgent),J="touch",K="pen",L="mouse",M="kinect",N=25,O=1,P=2,Q=4,R=8,S=1,T=2,U=4,V=8,W=16,X=T|U,Y=V|W,Z=X|Y,$=["x","y"],_=["clientX","clientY"];ab.prototype={handler:function(){},init:function(){this.evEl&&t(this.element,this.evEl,this.domHandler),this.evTarget&&t(this.target,this.evTarget,this.domHandler),this.evWin&&t(E(this.element),this.evWin,this.domHandler)},destroy:function(){this.evEl&&u(this.element,this.evEl,this.domHandler),this.evTarget&&u(this.target,this.evTarget,this.domHandler),this.evWin&&u(E(this.element),this.evWin,this.domHandler)}};var ob={mousedown:O,mousemove:P,mouseup:Q},pb="mousedown",qb="mousemove mouseup";p(rb,ab,{handler:function(a){var b=ob[a.type];b&O&&0===a.button&&(this.pressed=!0),b&P&&1!==a.which&&(b=Q),this.pressed&&this.allow&&(b&Q&&(this.pressed=!1),this.callback(this.manager,b,{pointers:[a],changedPointers:[a],pointerType:L,srcEvent:a}))}});var sb={pointerdown:O,pointermove:P,pointerup:Q,pointercancel:R,pointerout:R},tb={2:J,3:K,4:L,5:M},ub="pointerdown",vb="pointermove pointerup pointercancel";a.MSPointerEvent&&(ub="MSPointerDown",vb="MSPointerMove MSPointerUp MSPointerCancel"),p(wb,ab,{handler:function(a){var b=this.store,c=!1,d=a.type.toLowerCase().replace("ms",""),e=sb[d],f=tb[a.pointerType]||a.pointerType,g=f==J,h=y(b,a.pointerId,"pointerId");e&O&&(0===a.button||g)?0>h&&(b.push(a),h=b.length-1):e&(Q|R)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var xb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},yb="touchstart",zb="touchstart touchmove touchend touchcancel";p(Ab,ab,{handler:function(a){var b=xb[a.type];if(b===O&&(this.started=!0),this.started){var c=Bb.call(this,a,b);b&(Q|R)&&0===c[0].length-c[1].length&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}});var Cb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},Db="touchstart touchmove touchend touchcancel";p(Eb,ab,{handler:function(a){var b=Cb[a.type],c=Fb.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}),p(Gb,ab,{handler:function(a,b,c){var d=c.pointerType==J,e=c.pointerType==L;if(d)this.mouse.allow=!1;else if(e&&!this.mouse.allow)return;b&(Q|R)&&(this.mouse.allow=!0),this.callback(a,b,c)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var Hb=B(f.style,"touchAction"),Ib=Hb!==d,Jb="compute",Kb="auto",Lb="manipulation",Mb="none",Nb="pan-x",Ob="pan-y";Pb.prototype={set:function(a){a==Jb&&(a=this.compute()),Ib&&(this.manager.element.style[Hb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return m(this.manager.recognizers,function(b){r(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),Qb(a.join(" "))},preventDefaults:function(a){if(!Ib){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return b.preventDefault(),void 0;var d=this.actions,e=w(d,Mb),f=w(d,Ob),g=w(d,Nb);return e||f&&c&X||g&&c&Y?this.preventSrc(b):void 0}},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var Rb=1,Sb=2,Tb=4,Ub=8,Vb=Ub,Wb=16,Xb=32;Yb.prototype={defaults:{},set:function(a){return n(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(l(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_b(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return l(a,"dropRecognizeWith",this)?this:(a=_b(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(l(a,"requireFailure",this))return this;var b=this.requireFail;return a=_b(a,this),-1===y(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(l(a,"dropRequireFailure",this))return this;a=_b(a,this);var b=y(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function d(d){b.manager.emit(b.options.event+(d?Zb(c):""),a)}var b=this,c=this.state;Ub>c&&d(!0),d(),c>=Ub&&d(!0)},tryEmit:function(a){return this.canEmit()?this.emit(a):(this.state=Xb,void 0)},canEmit:function(){for(var a=0;a<this.requireFail.length;){if(!(this.requireFail[a].state&(Xb|Rb)))return!1;a++}return!0},recognize:function(a){var b=n({},a);return r(this.options.enable,[this,b])?(this.state&(Vb|Wb|Xb)&&(this.state=Rb),this.state=this.process(b),this.state&(Sb|Tb|Ub|Wb)&&this.tryEmit(b),void 0):(this.reset(),this.state=Xb,void 0)},process:function(){},getTouchAction:function(){},reset:function(){}},p(ac,Yb,{defaults:{pointers:1},attrTest:function(a){var b=this.options.pointers;return 0===b||a.pointers.length===b},process:function(a){var b=this.state,c=a.eventType,d=b&(Sb|Tb),e=this.attrTest(a);return d&&(c&R||!e)?b|Wb:d||e?c&Q?b|Ub:b&Sb?b|Tb:Sb:Xb}}),p(bc,ac,{defaults:{event:"pan",threshold:10,pointers:1,direction:Z},getTouchAction:function(){var a=this.options.direction,b=[];return a&X&&b.push(Ob),a&Y&&b.push(Nb),b},directionTest:function(a){var b=this.options,c=!0,d=a.distance,e=a.direction,f=a.deltaX,g=a.deltaY;return e&b.direction||(b.direction&X?(e=0===f?S:0>f?T:U,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?S:0>g?V:W,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return ac.prototype.attrTest.call(this,a)&&(this.state&Sb||!(this.state&Sb)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this._super.emit.call(this,a)}}),p(cc,ac,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&Sb)},emit:function(a){if(this._super.emit.call(this,a),1!==a.scale){var b=a.scale<1?"in":"out";this.manager.emit(this.options.event+b,a)}}}),p(dc,Yb,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[Kb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,e=a.deltaTime>b.time;if(this._input=a,!d||!c||a.eventType&(Q|R)&&!e)this.reset();else if(a.eventType&O)this.reset(),this._timer=k(function(){this.state=Vb,this.tryEmit()},b.time,this);else if(a.eventType&Q)return Vb;return Xb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===Vb&&(a&&a.eventType&Q?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=j(),this.manager.emit(this.options.event,this._input)))}}),p(ec,ac,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&Sb)}}),p(fc,ac,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:X|Y,pointers:1},getTouchAction:function(){return bc.prototype.getTouchAction.call(this)},attrTest:function(a){var c,b=this.options.direction;return b&(X|Y)?c=a.velocity:b&X?c=a.velocityX:b&Y&&(c=a.velocityY),this._super.attrTest.call(this,a)&&b&a.direction&&a.distance>this.options.threshold&&i(c)>this.options.velocity&&a.eventType&Q},emit:function(a){var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),p(gc,Yb,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[Lb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,e=a.deltaTime<b.time;if(this.reset(),a.eventType&O&&0===this.count)return this.failTimeout();if(d&&e&&c){if(a.eventType!=Q)return this.failTimeout();var f=this.pTime?a.timeStamp-this.pTime<b.interval:!0,g=!this.pCenter||kb(this.pCenter,a.center)<b.posThreshold;this.pTime=a.timeStamp,this.pCenter=a.center,g&&f?this.count+=1:this.count=1,this._input=a;var h=this.count%b.taps;if(0===h)return this.hasRequireFailures()?(this._timer=k(function(){this.state=Vb,this.tryEmit()},b.interval,this),Sb):Vb}return Xb},failTimeout:function(){return this._timer=k(function(){this.state=Xb},this.options.interval,this),Xb},reset:function(){clearTimeout(this._timer)},emit:function(){this.state==Vb&&(this._input.tapCount=this.count,this.manager.emit(this.options.event,this._input))}}),hc.VERSION="2.0.4",hc.defaults={domEvents:!1,touchAction:Jb,enable:!0,inputTarget:null,inputClass:null,preset:[[ec,{enable:!1}],[cc,{enable:!1},["rotate"]],[fc,{direction:X}],[bc,{direction:X},["swipe"]],[gc],[gc,{event:"doubletap",taps:2},["tap"]],[dc]],cssProps:{userSelect:"default",touchSelect:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}};var ic=1,jc=2;kc.prototype={set:function(a){return n(this.options,a),a.touchAction&&this.touchAction.update(),a.inputTarget&&(this.input.destroy(),this.input.target=a.inputTarget,this.input.init()),this},stop:function(a){this.session.stopped=a?jc:ic},recognize:function(a){var b=this.session;if(!b.stopped){this.touchAction.preventDefaults(a);var c,d=this.recognizers,e=b.curRecognizer;(!e||e&&e.state&Vb)&&(e=b.curRecognizer=null);for(var f=0;f<d.length;)c=d[f],b.stopped===jc||e&&c!=e&&!c.canRecognizeWith(e)?c.reset():c.recognize(a),!e&&c.state&(Sb|Tb|Ub)&&(e=b.curRecognizer=c),f++}},get:function(a){if(a instanceof Yb)return a;for(var b=this.recognizers,c=0;c<b.length;c++)if(b[c].options.event==a)return b[c];return null},add:function(a){if(l(a,"add",this))return this;var b=this.get(a.options.event);return b&&this.remove(b),this.recognizers.push(a),a.manager=this,this.touchAction.update(),a},remove:function(a){if(l(a,"remove",this))return this;var b=this.recognizers;return a=this.get(a),b.splice(y(b,a),1),this.touchAction.update(),this},on:function(a,b){var c=this.handlers;return m(x(a),function(a){c[a]=c[a]||[],c[a].push(b)}),this},off:function(a,b){var c=this.handlers;return m(x(a),function(a){b?c[a].splice(y(c[a],b),1):delete c[a]}),this},emit:function(a,b){this.options.domEvents&&mc(a,b);var c=this.handlers[a]&&this.handlers[a].slice();if(c&&c.length){b.type=a,b.preventDefault=function(){b.srcEvent.preventDefault()};for(var d=0;d<c.length;)c[d](b),d++}},destroy:function(){this.element&&lc(this,!1),this.handlers={},this.session={},this.input.destroy(),this.element=null}},n(hc,{INPUT_START:O,INPUT_MOVE:P,INPUT_END:Q,INPUT_CANCEL:R,STATE_POSSIBLE:Rb,STATE_BEGAN:Sb,STATE_CHANGED:Tb,STATE_ENDED:Ub,STATE_RECOGNIZED:Vb,STATE_CANCELLED:Wb,STATE_FAILED:Xb,DIRECTION_NONE:S,DIRECTION_LEFT:T,DIRECTION_RIGHT:U,DIRECTION_UP:V,DIRECTION_DOWN:W,DIRECTION_HORIZONTAL:X,DIRECTION_VERTICAL:Y,DIRECTION_ALL:Z,Manager:kc,Input:ab,TouchAction:Pb,TouchInput:Eb,MouseInput:rb,PointerEventInput:wb,TouchMouseInput:Gb,SingleTouchInput:Ab,Recognizer:Yb,AttrRecognizer:ac,Tap:gc,Pan:bc,Swipe:fc,Pinch:cc,Rotate:ec,Press:dc,on:t,off:u,each:m,merge:o,extend:n,inherit:p,bindFn:q,prefixed:B}),typeof define==g&&define.amd?define(function(){return hc}):"undefined"!=typeof module&&module.exports?module.exports=hc:a[c]=hc}(window,document,"Hammer");;(function(factory) {
-    if (typeof define === 'function' && define.amd) {
-        define(['jquery', 'hammerjs'], factory);
-    } else if (typeof exports === 'object') {
-        factory(require('jquery'), require('hammerjs'));
-    } else {
-        factory(jQuery, Hammer);
-    }
-}(function($, Hammer) {
-    function hammerify(el, options) {
-        var $el = $(el);
-        if(!$el.data("hammer")) {
-            $el.data("hammer", new Hammer($el[0], options));
-        }
-    }
-
-    $.fn.hammer = function(options) {
-        return this.each(function() {
-            hammerify(this, options);
-        });
-    };
-
-    // extend the emit method to also trigger jQuery events
-    Hammer.Manager.prototype.emit = (function(originalEmit) {
-        return function(type, data) {
-            originalEmit.call(this, type, data);
-            $(this.element).trigger({
-                type: type,
-                gesture: data
-            });
-        };
-    })(Hammer.Manager.prototype.emit);
-}));
-;// Required for Meteor package, the use of window prevents export by Meteor
-(function(window){
-  if(window.Package){
-    Materialize = {};
-  } else {
-    window.Materialize = {};
-  }
-})(window);
-
-
-/*
- * raf.js
- * https://github.com/ngryman/raf.js
- *
- * original requestAnimationFrame polyfill by Erik Möller
- * inspired from paul_irish gist and post
- *
- * Copyright (c) 2013 ngryman
- * Licensed under the MIT license.
- */
-(function(window) {
-  var lastTime = 0,
-    vendors = ['webkit', 'moz'],
-    requestAnimationFrame = window.requestAnimationFrame,
-    cancelAnimationFrame = window.cancelAnimationFrame,
-    i = vendors.length;
-
-  // try to un-prefix existing raf
-  while (--i >= 0 && !requestAnimationFrame) {
-    requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame'];
-    cancelAnimationFrame = window[vendors[i] + 'CancelRequestAnimationFrame'];
-  }
-
-  // polyfill with setTimeout fallback
-  // heavily inspired from @darius gist mod: https://gist.github.com/paulirish/1579671#comment-837945
-  if (!requestAnimationFrame || !cancelAnimationFrame) {
-    requestAnimationFrame = function(callback) {
-      var now = +Date.now(),
-        nextTime = Math.max(lastTime + 16, now);
-      return setTimeout(function() {
-        callback(lastTime = nextTime);
-      }, nextTime - now);
-    };
-
-    cancelAnimationFrame = clearTimeout;
-  }
-
-  // export to window
-  window.requestAnimationFrame = requestAnimationFrame;
-  window.cancelAnimationFrame = cancelAnimationFrame;
-}(window));
-
-
-// Unique ID
-Materialize.guid = (function() {
-  function s4() {
-    return Math.floor((1 + Math.random()) * 0x10000)
-      .toString(16)
-      .substring(1);
-  }
-  return function() {
-    return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
-           s4() + '-' + s4() + s4() + s4();
-  };
-})();
-
-/**
- * Escapes hash from special characters
- * @param {string} hash  String returned from this.hash
- * @returns {string}
- */
-Materialize.escapeHash = function(hash) {
-  return hash.replace( /(:|\.|\[|\]|,|=)/g, "\\$1" );
-};
-
-Materialize.elementOrParentIsFixed = function(element) {
-    var $element = $(element);
-    var $checkElements = $element.add($element.parents());
-    var isFixed = false;
-    $checkElements.each(function(){
-        if ($(this).css("position") === "fixed") {
-            isFixed = true;
-            return false;
-        }
-    });
-    return isFixed;
-};
-
-
-/**
- * Get time in ms
- * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
- * @type {function}
- * @return {number}
- */
-var getTime = (Date.now || function () {
-  return new Date().getTime();
-});
-
-
-/**
- * Returns a function, that, when invoked, will only be triggered at most once
- * during a given window of time. Normally, the throttled function will run
- * as much as it can, without ever going more than once per `wait` duration;
- * but if you'd like to disable the execution on the leading edge, pass
- * `{leading: false}`. To disable execution on the trailing edge, ditto.
- * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
- * @param {function} func
- * @param {number} wait
- * @param {Object=} options
- * @returns {Function}
- */
-Materialize.throttle = function(func, wait, options) {
-  var context, args, result;
-  var timeout = null;
-  var previous = 0;
-  options || (options = {});
-  var later = function () {
-    previous = options.leading === false ? 0 : getTime();
-    timeout = null;
-    result = func.apply(context, args);
-    context = args = null;
-  };
-  return function () {
-    var now = getTime();
-    if (!previous && options.leading === false) previous = now;
-    var remaining = wait - (now - previous);
-    context = this;
-    args = arguments;
-    if (remaining <= 0) {
-      clearTimeout(timeout);
-      timeout = null;
-      previous = now;
-      result = func.apply(context, args);
-      context = args = null;
-    } else if (!timeout && options.trailing !== false) {
-      timeout = setTimeout(later, remaining);
-    }
-    return result;
-  };
-};
-
-
-// Velocity has conflicts when loaded with jQuery, this will check for it
-// First, check if in noConflict mode
-var Vel;
-if (jQuery) {
-  Vel = jQuery.Velocity;
-} else if ($) {
-  Vel = $.Velocity;
-} else {
-  Vel = Velocity;
-}
-;(function ($) {
-  $.fn.collapsible = function(options) {
-    var defaults = {
-      accordion: undefined,
-      onOpen: undefined,
-      onClose: undefined
-    };
-
-    options = $.extend(defaults, options);
-
-
-    return this.each(function() {
-
-      var $this = $(this);
-
-      var $panel_headers = $(this).find('> li > .collapsible-header');
-
-      var collapsible_type = $this.data("collapsible");
-
-      // Turn off any existing event handlers
-      $this.off('click.collapse', '> li > .collapsible-header');
-      $panel_headers.off('click.collapse');
-
-
-      /****************
-      Helper Functions
-      ****************/
-
-      // Accordion Open
-      function accordionOpen(object) {
-        $panel_headers = $this.find('> li > .collapsible-header');
-        if (object.hasClass('active')) {
-          object.parent().addClass('active');
-        }
-        else {
-          object.parent().removeClass('active');
-        }
-        if (object.parent().hasClass('active')){
-          object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
-        }
-        else{
-          object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
-        }
-
-        $panel_headers.not(object).removeClass('active').parent().removeClass('active');
-
-        // Close previously open accordion elements.
-        $panel_headers.not(object).parent().children('.collapsible-body').stop(true,false).each(function() {
-          if ($(this).is(':visible')) {
-            $(this).slideUp({
-              duration: 350,
-              easing: "easeOutQuart",
-              queue: false,
-              complete:
-                function() {
-                  $(this).css('height', '');
-                  execCallbacks($(this).siblings('.collapsible-header'));
-                }
-            });
-          }
-        });
-      }
-
-      // Expandable Open
-      function expandableOpen(object) {
-        if (object.hasClass('active')) {
-          object.parent().addClass('active');
-        }
-        else {
-          object.parent().removeClass('active');
-        }
-        if (object.parent().hasClass('active')){
-          object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
-        }
-        else {
-          object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
-        }
-      }
-
-      // Open collapsible. object: .collapsible-header
-      function collapsibleOpen(object) {
-        if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion
-          accordionOpen(object);
-        } else { // Handle Expandables
-          expandableOpen(object);
-        }
-
-        execCallbacks(object);
-      }
-
-      // Handle callbacks
-      function execCallbacks(object) {
-        if (object.hasClass('active')) {
-          if (typeof(options.onOpen) === "function") {
-            options.onOpen.call(this, object.parent());
-          }
-        } else {
-          if (typeof(options.onClose) === "function") {
-            options.onClose.call(this, object.parent());
-          }
-        }
-      }
-
-      /**
-       * Check if object is children of panel header
-       * @param  {Object}  object Jquery object
-       * @return {Boolean} true if it is children
-       */
-      function isChildrenOfPanelHeader(object) {
-
-        var panelHeader = getPanelHeader(object);
-
-        return panelHeader.length > 0;
-      }
-
-      /**
-       * Get panel header from a children element
-       * @param  {Object} object Jquery object
-       * @return {Object} panel header object
-       */
-      function getPanelHeader(object) {
-
-        return object.closest('li > .collapsible-header');
-      }
-
-      /*****  End Helper Functions  *****/
-
-
-
-      // Add click handler to only direct collapsible header children
-      $this.on('click.collapse', '> li > .collapsible-header', function(e) {
-        var element = $(e.target);
-
-        if (isChildrenOfPanelHeader(element)) {
-          element = getPanelHeader(element);
-        }
-
-        element.toggleClass('active');
-
-        collapsibleOpen(element);
-      });
-
-
-      // Open first active
-      if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion
-        collapsibleOpen($panel_headers.filter('.active').first());
-
-      } else { // Handle Expandables
-        $panel_headers.filter('.active').each(function() {
-          collapsibleOpen($(this));
-        });
-      }
-
-    });
-  };
-
-  $(document).ready(function(){
-    $('.collapsible').collapsible();
-  });
-}( jQuery ));;(function ($) {
-
-  // Add posibility to scroll to selected option
-  // usefull for select for example
-  $.fn.scrollTo = function(elem) {
-    $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top);
-    return this;
-  };
-
-  $.fn.dropdown = function (options) {
-    var defaults = {
-      inDuration: 300,
-      outDuration: 225,
-      constrainWidth: true, // Constrains width of dropdown to the activator
-      hover: false,
-      gutter: 0, // Spacing from edge
-      belowOrigin: false,
-      alignment: 'left',
-      stopPropagation: false
-    };
-
-    // Open dropdown.
-    if (options === "open") {
-      this.each(function() {
-        $(this).trigger('open');
-      });
-      return false;
-    }
-
-    // Close dropdown.
-    if (options === "close") {
-      this.each(function() {
-        $(this).trigger('close');
-      });
-      return false;
-    }
-
-    this.each(function(){
-      var origin = $(this);
-      var curr_options = $.extend({}, defaults, options);
-      var isFocused = false;
-
-      // Dropdown menu
-      var activates = $("#"+ origin.attr('data-activates'));
-
-      function updateOptions() {
-        if (origin.data('induration') !== undefined)
-          curr_options.inDuration = origin.data('induration');
-        if (origin.data('outduration') !== undefined)
-          curr_options.outDuration = origin.data('outduration');
-        if (origin.data('constrainwidth') !== undefined)
-          curr_options.constrainWidth = origin.data('constrainwidth');
-        if (origin.data('hover') !== undefined)
-          curr_options.hover = origin.data('hover');
-        if (origin.data('gutter') !== undefined)
-          curr_options.gutter = origin.data('gutter');
-        if (origin.data('beloworigin') !== undefined)
-          curr_options.belowOrigin = origin.data('beloworigin');
-        if (origin.data('alignment') !== undefined)
-          curr_options.alignment = origin.data('alignment');
-        if (origin.data('stoppropagation') !== undefined)
-          curr_options.stopPropagation = origin.data('stoppropagation');
-      }
-
-      updateOptions();
-
-      // Attach dropdown to its activator
-      origin.after(activates);
-
-      /*
-        Helper function to position and resize dropdown.
-        Used in hover and click handler.
-      */
-      function placeDropdown(eventType) {
-        // Check for simultaneous focus and click events.
-        if (eventType === 'focus') {
-          isFocused = true;
-        }
-
-        // Check html data attributes
-        updateOptions();
-
-        // Set Dropdown state
-        activates.addClass('active');
-        origin.addClass('active');
-
-        // Constrain width
-        if (curr_options.constrainWidth === true) {
-          activates.css('width', origin.outerWidth());
-
-        } else {
-          activates.css('white-space', 'nowrap');
-        }
-
-        // Offscreen detection
-        var windowHeight = window.innerHeight;
-        var originHeight = origin.innerHeight();
-        var offsetLeft = origin.offset().left;
-        var offsetTop = origin.offset().top - $(window).scrollTop();
-        var currAlignment = curr_options.alignment;
-        var gutterSpacing = 0;
-        var leftPosition = 0;
-
-        // Below Origin
-        var verticalOffset = 0;
-        if (curr_options.belowOrigin === true) {
-          verticalOffset = originHeight;
-        }
-
-        // Check for scrolling positioned container.
-        var scrollYOffset = 0;
-        var scrollXOffset = 0;
-        var wrapper = origin.parent();
-        if (!wrapper.is('body')) {
-          if (wrapper[0].scrollHeight > wrapper[0].clientHeight) {
-            scrollYOffset = wrapper[0].scrollTop;
-          }
-          if (wrapper[0].scrollWidth > wrapper[0].clientWidth) {
-            scrollXOffset = wrapper[0].scrollLeft;
-          }
-        }
-
-
-        if (offsetLeft + activates.innerWidth() > $(window).width()) {
-          // Dropdown goes past screen on right, force right alignment
-          currAlignment = 'right';
-
-        } else if (offsetLeft - activates.innerWidth() + origin.innerWidth() < 0) {
-          // Dropdown goes past screen on left, force left alignment
-          currAlignment = 'left';
-        }
-        // Vertical bottom offscreen detection
-        if (offsetTop + activates.innerHeight() > windowHeight) {
-          // If going upwards still goes offscreen, just crop height of dropdown.
-          if (offsetTop + originHeight - activates.innerHeight() < 0) {
-            var adjustedHeight = windowHeight - offsetTop - verticalOffset;
-            activates.css('max-height', adjustedHeight);
-          } else {
-            // Flow upwards.
-            if (!verticalOffset) {
-              verticalOffset += originHeight;
-            }
-            verticalOffset -= activates.innerHeight();
-          }
-        }
-
-        // Handle edge alignment
-        if (currAlignment === 'left') {
-          gutterSpacing = curr_options.gutter;
-          leftPosition = origin.position().left + gutterSpacing;
-        }
-        else if (currAlignment === 'right') {
-          var offsetRight = origin.position().left + origin.outerWidth() - activates.outerWidth();
-          gutterSpacing = -curr_options.gutter;
-          leftPosition =  offsetRight + gutterSpacing;
-        }
-
-        // Position dropdown
-        activates.css({
-          position: 'absolute',
-          top: origin.position().top + verticalOffset + scrollYOffset,
-          left: leftPosition + scrollXOffset
-        });
-
-
-        // Show dropdown
-        activates.stop(true, true).css('opacity', 0)
-          .slideDown({
-            queue: false,
-            duration: curr_options.inDuration,
-            easing: 'easeOutCubic',
-            complete: function() {
-              $(this).css('height', '');
-            }
-          })
-          .animate( {opacity: 1}, {queue: false, duration: curr_options.inDuration, easing: 'easeOutSine'});
-
-        // Add click close handler to document
-        $(document).bind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id'), function (e) {
-          if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length) ) {
-            hideDropdown();
-            $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id'));
-          }
-        });
-      }
-
-      function hideDropdown() {
-        // Check for simultaneous focus and click events.
-        isFocused = false;
-        activates.fadeOut(curr_options.outDuration);
-        activates.removeClass('active');
-        origin.removeClass('active');
-        $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id'));
-        setTimeout(function() { activates.css('max-height', ''); }, curr_options.outDuration);
-      }
-
-      // Hover
-      if (curr_options.hover) {
-        var open = false;
-        origin.unbind('click.' + origin.attr('id'));
-        // Hover handler to show dropdown
-        origin.on('mouseenter', function(e){ // Mouse over
-          if (open === false) {
-            placeDropdown();
-            open = true;
-          }
-        });
-        origin.on('mouseleave', function(e){
-          // If hover on origin then to something other than dropdown content, then close
-          var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element
-          if(!$(toEl).closest('.dropdown-content').is(activates)) {
-            activates.stop(true, true);
-            hideDropdown();
-            open = false;
-          }
-        });
-
-        activates.on('mouseleave', function(e){ // Mouse out
-          var toEl = e.toElement || e.relatedTarget;
-          if(!$(toEl).closest('.dropdown-button').is(origin)) {
-            activates.stop(true, true);
-            hideDropdown();
-            open = false;
-          }
-        });
-
-        // Click
-      } else {
-        // Click handler to show dropdown
-        origin.unbind('click.' + origin.attr('id'));
-        origin.bind('click.'+origin.attr('id'), function(e){
-          if (!isFocused) {
-            if ( origin[0] == e.currentTarget &&
-                 !origin.hasClass('active') &&
-                 ($(e.target).closest('.dropdown-content').length === 0)) {
-              e.preventDefault(); // Prevents button click from moving window
-              if (curr_options.stopPropagation) {
-                e.stopPropagation();
-              }
-              placeDropdown('click');
-            }
-            // If origin is clicked and menu is open, close menu
-            else if (origin.hasClass('active')) {
-              hideDropdown();
-              $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id'));
-            }
-          }
-        });
-
-      } // End else
-
-      // Listen to open and close event - useful for select component
-      origin.on('open', function(e, eventType) {
-        placeDropdown(eventType);
-      });
-      origin.on('close', hideDropdown);
-
-
-    });
-  }; // End dropdown plugin
-
-  $(document).ready(function(){
-    $('.dropdown-button').dropdown();
-  });
-}( jQuery ));
-;(function($) {
-  var _stack = 0,
-  _lastID = 0,
-  _generateID = function() {
-    _lastID++;
-    return 'materialize-modal-overlay-' + _lastID;
-  };
-
-  var methods = {
-    init : function(options) {
-      var defaults = {
-        opacity: 0.5,
-        inDuration: 350,
-        outDuration: 250,
-        ready: undefined,
-        complete: undefined,
-        dismissible: true,
-        startingTop: '4%',
-        endingTop: '10%'
-      };
-
-      // Override defaults
-      options = $.extend(defaults, options);
-
-      return this.each(function() {
-        var $modal = $(this);
-        var modal_id = $(this).attr("id") || '#' + $(this).data('target');
-
-        var closeModal = function() {
-          var overlayID = $modal.data('overlay-id');
-          var $overlay = $('#' + overlayID);
-          $modal.removeClass('open');
-
-          // Enable scrolling
-          $('body').css({
-            overflow: '',
-            width: ''
-          });
-
-          $modal.find('.modal-close').off('click.close');
-          $(document).off('keyup.modal' + overlayID);
-
-          $overlay.velocity( { opacity: 0}, {duration: options.outDuration, queue: false, ease: "easeOutQuart"});
-
-
-          // Define Bottom Sheet animation
-          var exitVelocityOptions = {
-            duration: options.outDuration,
-            queue: false,
-            ease: "easeOutCubic",
-            // Handle modal ready callback
-            complete: function() {
-              $(this).css({display:"none"});
-
-              // Call complete callback
-              if (typeof(options.complete) === "function") {
-                options.complete.call(this, $modal);
-              }
-              $overlay.remove();
-              _stack--;
-            }
-          };
-          if ($modal.hasClass('bottom-sheet')) {
-            $modal.velocity({bottom: "-100%", opacity: 0}, exitVelocityOptions);
-          }
-          else {
-            $modal.velocity(
-              { top: options.startingTop, opacity: 0, scaleX: 0.7},
-              exitVelocityOptions
-            );
-          }
-        };
-
-        var openModal = function($trigger) {
-          var $body = $('body');
-          var oldWidth = $body.innerWidth();
-          $body.css('overflow', 'hidden');
-          $body.width(oldWidth);
-
-          if ($modal.hasClass('open')) {
-            return;
-          }
-
-          var overlayID = _generateID();
-          var $overlay = $('<div class="modal-overlay"></div>');
-          lStack = (++_stack);
-
-          // Store a reference of the overlay
-          $overlay.attr('id', overlayID).css('z-index', 1000 + lStack * 2);
-          $modal.data('overlay-id', overlayID).css('z-index', 1000 + lStack * 2 + 1);
-          $modal.addClass('open');
-
-          $("body").append($overlay);
-
-          if (options.dismissible) {
-            $overlay.click(function() {
-              closeModal();
-            });
-            // Return on ESC
-            $(document).on('keyup.modal' + overlayID, function(e) {
-              if (e.keyCode === 27) {   // ESC key
-                closeModal();
-              }
-            });
-          }
-
-          $modal.find(".modal-close").on('click.close', function(e) {
-            closeModal();
-          });
-
-          $overlay.css({ display : "block", opacity : 0 });
-
-          $modal.css({
-            display : "block",
-            opacity: 0
-          });
-
-          $overlay.velocity({opacity: options.opacity}, {duration: options.inDuration, queue: false, ease: "easeOutCubic"});
-          $modal.data('associated-overlay', $overlay[0]);
-
-          // Define Bottom Sheet animation
-          var enterVelocityOptions = {
-            duration: options.inDuration,
-            queue: false,
-            ease: "easeOutCubic",
-            // Handle modal ready callback
-            complete: function() {
-              if (typeof(options.ready) === "function") {
-                options.ready.call(this, $modal, $trigger);
-              }
-            }
-          };
-          if ($modal.hasClass('bottom-sheet')) {
-            $modal.velocity({bottom: "0", opacity: 1}, enterVelocityOptions);
-          }
-          else {
-            $.Velocity.hook($modal, "scaleX", 0.7);
-            $modal.css({ top: options.startingTop });
-            $modal.velocity({top: options.endingTop, opacity: 1, scaleX: '1'}, enterVelocityOptions);
-          }
-
-        };
-
-        // Reset handlers
-        $(document).off('click.modalTrigger', 'a[href="#' + modal_id + '"], [data-target="' + modal_id + '"]');
-        $(this).off('openModal');
-        $(this).off('closeModal');
-
-        // Close Handlers
-        $(document).on('click.modalTrigger', 'a[href="#' + modal_id + '"], [data-target="' + modal_id + '"]', function(e) {
-          options.startingTop = ($(this).offset().top - $(window).scrollTop()) /1.15;
-          openModal($(this));
-          e.preventDefault();
-        }); // done set on click
-
-        $(this).on('openModal', function() {
-          var modal_id = $(this).attr("href") || '#' + $(this).data('target');
-          openModal();
-        });
-
-        $(this).on('closeModal', function() {
-          closeModal();
-        });
-      }); // done return
-    },
-    open : function() {
-      $(this).trigger('openModal');
-    },
-    close : function() {
-      $(this).trigger('closeModal');
-    }
-  };
-
-  $.fn.modal = function(methodOrOptions) {
-    if ( methods[methodOrOptions] ) {
-      return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
-    } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
-      // Default to "init"
-      return methods.init.apply( this, arguments );
-    } else {
-      $.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.modal' );
-    }
-  };
-})(jQuery);
-;(function ($) {
-
-  $.fn.materialbox = function () {
-
-    return this.each(function() {
-
-      if ($(this).hasClass('initialized')) {
-        return;
-      }
-
-      $(this).addClass('initialized');
-
-      var overlayActive = false;
-      var doneAnimating = true;
-      var inDuration = 275;
-      var outDuration = 200;
-      var origin = $(this);
-      var placeholder = $('<div></div>').addClass('material-placeholder');
-      var originalWidth = 0;
-      var originalHeight = 0;
-      var ancestorsChanged;
-      var ancestor;
-      origin.wrap(placeholder);
-
-
-      origin.on('click', function(){
-        var placeholder = origin.parent('.material-placeholder');
-        var windowWidth = window.innerWidth;
-        var windowHeight = window.innerHeight;
-        var originalWidth = origin.width();
-        var originalHeight = origin.height();
-
-
-        // If already modal, return to original
-        if (doneAnimating === false) {
-          returnToOriginal();
-          return false;
-        }
-        else if (overlayActive && doneAnimating===true) {
-          returnToOriginal();
-          return false;
-        }
-
-
-        // Set states
-        doneAnimating = false;
-        origin.addClass('active');
-        overlayActive = true;
-
-        // Set positioning for placeholder
-        placeholder.css({
-          width: placeholder[0].getBoundingClientRect().width,
-          height: placeholder[0].getBoundingClientRect().height,
-          position: 'relative',
-          top: 0,
-          left: 0
-        });
-
-        // Find ancestor with overflow: hidden; and remove it
-        ancestorsChanged = undefined;
-        ancestor = placeholder[0].parentNode;
-        var count = 0;
-        while (ancestor !== null && !$(ancestor).is(document)) {
-          var curr = $(ancestor);
-          if (curr.css('overflow') !== 'visible') {
-            curr.css('overflow', 'visible');
-            if (ancestorsChanged === undefined) {
-              ancestorsChanged = curr;
-            }
-            else {
-              ancestorsChanged = ancestorsChanged.add(curr);
-            }
-          }
-          ancestor = ancestor.parentNode;
-        }
-
-        // Set css on origin
-        origin.css({
-          position: 'absolute',
-          'z-index': 1000,
-          'will-change': 'left, top, width, height'
-        })
-        .data('width', originalWidth)
-        .data('height', originalHeight);
-
-        // Add overlay
-        var overlay = $('<div id="materialbox-overlay"></div>')
-          .css({
-            opacity: 0
-          })
-          .click(function(){
-            if (doneAnimating === true)
-            returnToOriginal();
-          });
-
-        // Put before in origin image to preserve z-index layering.
-        origin.before(overlay);
-
-        // Set dimensions if needed
-        var overlayOffset = overlay[0].getBoundingClientRect();
-        overlay.css({
-          width: windowWidth,
-          height: windowHeight,
-          left: -1 * overlayOffset.left,
-          top: -1 * overlayOffset.top
-        })
-
-        // Animate Overlay
-        overlay.velocity({opacity: 1},
-                           {duration: inDuration, queue: false, easing: 'easeOutQuad'} );
-
-        // Add and animate caption if it exists
-        if (origin.data('caption') !== "") {
-          var $photo_caption = $('<div class="materialbox-caption"></div>');
-          $photo_caption.text(origin.data('caption'));
-          $('body').append($photo_caption);
-          $photo_caption.css({ "display": "inline" });
-          $photo_caption.velocity({opacity: 1}, {duration: inDuration, queue: false, easing: 'easeOutQuad'});
-        }
-
-        // Resize Image
-        var ratio = 0;
-        var widthPercent = originalWidth / windowWidth;
-        var heightPercent = originalHeight / windowHeight;
-        var newWidth = 0;
-        var newHeight = 0;
-
-        if (widthPercent > heightPercent) {
-          ratio = originalHeight / originalWidth;
-          newWidth = windowWidth * 0.9;
-          newHeight = windowWidth * 0.9 * ratio;
-        }
-        else {
-          ratio = originalWidth / originalHeight;
-          newWidth = (windowHeight * 0.9) * ratio;
-          newHeight = windowHeight * 0.9;
-        }
-
-        // Animate image + set z-index
-        if(origin.hasClass('responsive-img')) {
-          origin.velocity({'max-width': newWidth, 'width': originalWidth}, {duration: 0, queue: false,
-            complete: function(){
-              origin.css({left: 0, top: 0})
-              .velocity(
-                {
-                  height: newHeight,
-                  width: newWidth,
-                  left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2,
-                  top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2
-                },
-                {
-                  duration: inDuration,
-                  queue: false,
-                  easing: 'easeOutQuad',
-                  complete: function(){doneAnimating = true;}
-                }
-              );
-            } // End Complete
-          }); // End Velocity
-        }
-        else {
-          origin.css('left', 0)
-          .css('top', 0)
-          .velocity(
-            {
-              height: newHeight,
-              width: newWidth,
-              left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2,
-              top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2
-            },
-            {
-              duration: inDuration,
-              queue: false,
-              easing: 'easeOutQuad',
-              complete: function(){doneAnimating = true;}
-            }
-            ); // End Velocity
-        }
-
-      }); // End origin on click
-
-
-      // Return on scroll
-      $(window).scroll(function() {
-        if (overlayActive) {
-          returnToOriginal();
-        }
-      });
-
-      // Return on ESC
-      $(document).keyup(function(e) {
-
-        if (e.keyCode === 27 && doneAnimating === true) {   // ESC key
-          if (overlayActive) {
-            returnToOriginal();
-          }
-        }
-      });
-
-
-      // This function returns the modaled image to the original spot
-      function returnToOriginal() {
-
-        doneAnimating = false;
-
-        var placeholder = origin.parent('.material-placeholder');
-        var windowWidth = window.innerWidth;
-        var windowHeight = window.innerHeight;
-        var originalWidth = origin.data('width');
-        var originalHeight = origin.data('height');
-
-        origin.velocity("stop", true);
-        $('#materialbox-overlay').velocity("stop", true);
-        $('.materialbox-caption').velocity("stop", true);
-
-
-        $('#materialbox-overlay').velocity({opacity: 0}, {
-          duration: outDuration, // Delay prevents animation overlapping
-          queue: false, easing: 'easeOutQuad',
-          complete: function(){
-            // Remove Overlay
-            overlayActive = false;
-            $(this).remove();
-          }
-        });
-
-        // Resize Image
-        origin.velocity(
-          {
-            width: originalWidth,
-            height: originalHeight,
-            left: 0,
-            top: 0
-          },
-          {
-            duration: outDuration,
-            queue: false, easing: 'easeOutQuad'
-          }
-        );
-
-        // Remove Caption + reset css settings on image
-        $('.materialbox-caption').velocity({opacity: 0}, {
-          duration: outDuration, // Delay prevents animation overlapping
-          queue: false, easing: 'easeOutQuad',
-          complete: function(){
-            placeholder.css({
-              height: '',
-              width: '',
-              position: '',
-              top: '',
-              left: ''
-            });
-
-            origin.css({
-              height: '',
-              top: '',
-              left: '',
-              width: '',
-              'max-width': '',
-              position: '',
-              'z-index': '',
-              'will-change': ''
-            });
-
-            // Remove class
-            origin.removeClass('active');
-            doneAnimating = true;
-            $(this).remove();
-
-            // Remove overflow overrides on ancestors
-            if (ancestorsChanged) {
-              ancestorsChanged.css('overflow', '');
-            }
-          }
-        });
-
-      }
-    });
-  };
-
-  $(document).ready(function(){
-    $('.materialboxed').materialbox();
-  });
-
-}( jQuery ));
-;(function ($) {
-
-  $.fn.parallax = function () {
-    var window_width = $(window).width();
-    // Parallax Scripts
-    return this.each(function(i) {
-      var $this = $(this);
-      $this.addClass('parallax');
-
-      function updateParallax(initial) {
-        var container_height;
-        if (window_width < 601) {
-          container_height = ($this.height() > 0) ? $this.height() : $this.children("img").height();
-        }
-        else {
-          container_height = ($this.height() > 0) ? $this.height() : 500;
-        }
-        var $img = $this.children("img").first();
-        var img_height = $img.height();
-        var parallax_dist = img_height - container_height;
-        var bottom = $this.offset().top + container_height;
-        var top = $this.offset().top;
-        var scrollTop = $(window).scrollTop();
-        var windowHeight = window.innerHeight;
-        var windowBottom = scrollTop + windowHeight;
-        var percentScrolled = (windowBottom - top) / (container_height + windowHeight);
-        var parallax = Math.round((parallax_dist * percentScrolled));
-
-        if (initial) {
-          $img.css('display', 'block');
-        }
-        if ((bottom > scrollTop) && (top < (scrollTop + windowHeight))) {
-          $img.css('transform', "translate3D(-50%," + parallax + "px, 0)");
-        }
-
-      }
-
-      // Wait for image load
-      $this.children("img").one("load", function() {
-        updateParallax(true);
-      }).each(function() {
-        if (this.complete) $(this).trigger("load");
-      });
-
-      $(window).scroll(function() {
-        window_width = $(window).width();
-        updateParallax(false);
-      });
-
-      $(window).resize(function() {
-        window_width = $(window).width();
-        updateParallax(false);
-      });
-
-    });
-
-  };
-}( jQuery ));
-;(function ($) {
-
-  var methods = {
-    init : function(options) {
-      var defaults = {
-        onShow: null,
-        swipeable: false,
-        responsiveThreshold: Infinity, // breakpoint for swipeable
-      };
-      options = $.extend(defaults, options);
-
-      return this.each(function() {
-
-      // For each set of tabs, we want to keep track of
-      // which tab is active and its associated content
-      var $this = $(this),
-          window_width = $(window).width();
-
-      var $active, $content, $links = $this.find('li.tab a'),
-          $tabs_width = $this.width(),
-          $tabs_content = $(),
-          $tabs_wrapper,
-          $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length,
-          $indicator,
-          index = prev_index = 0,
-          clicked = false,
-          clickedTimeout,
-          transition = 300;
-
-
-      // Finds right attribute for indicator based on active tab.
-      // el: jQuery Object
-      var calcRightPos = function(el) {
-        return $tabs_width - el.position().left - el.outerWidth() - $this.scrollLeft();
-      };
-
-      // Finds left attribute for indicator based on active tab.
-      // el: jQuery Object
-      var calcLeftPos = function(el) {
-        return el.position().left + $this.scrollLeft();
-      };
-
-      // Animates Indicator to active tab.
-      // prev_index: Number
-      var animateIndicator = function(prev_index) {
-        if ((index - prev_index) >= 0) {
-          $indicator.velocity({"right": calcRightPos($active) }, { duration: transition, queue: false, easing: 'easeOutQuad'});
-          $indicator.velocity({"left": calcLeftPos($active) }, {duration: transition, queue: false, easing: 'easeOutQuad', delay: 90});
-
-        } else {
-          $indicator.velocity({"left": calcLeftPos($active) }, { duration: transition, queue: false, easing: 'easeOutQuad'});
-          $indicator.velocity({"right": calcRightPos($active) }, {duration: transition, queue: false, easing: 'easeOutQuad', delay: 90});
-        }
-      };
-
-      // Change swipeable according to responsive threshold
-      if (options.swipeable) {
-        if (window_width > options.responsiveThreshold) {
-          options.swipeable = false;
-        }
-      }
-
-
-      // If the location.hash matches one of the links, use that as the active tab.
-      $active = $($links.filter('[href="'+location.hash+'"]'));
-
-      // If no match is found, use the first link or any with class 'active' as the initial active tab.
-      if ($active.length === 0) {
-        $active = $(this).find('li.tab a.active').first();
-      }
-      if ($active.length === 0) {
-        $active = $(this).find('li.tab a').first();
-      }
-
-      $active.addClass('active');
-      index = $links.index($active);
-      if (index < 0) {
-        index = 0;
-      }
-
-      if ($active[0] !== undefined) {
-        $content = $($active[0].hash);
-        $content.addClass('active');
-      }
-
-      // append indicator then set indicator width to tab width
-      if (!$this.find('.indicator').length) {
-        $this.append('<div class="indicator"></div>');
-      }
-      $indicator = $this.find('.indicator');
-
-      // we make sure that the indicator is at the end of the tabs
-      $this.append($indicator);
-
-      if ($this.is(":visible")) {
-        // $indicator.css({"right": $tabs_width - ((index + 1) * $tab_width)});
-        // $indicator.css({"left": index * $tab_width});
-        setTimeout(function() {
-          $indicator.css({"right": calcRightPos($active) });
-          $indicator.css({"left": calcLeftPos($active) });
-        }, 0);
-      }
-      $(window).resize(function () {
-        $tabs_width = $this.width();
-        $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length;
-        if (index < 0) {
-          index = 0;
-        }
-        if ($tab_width !== 0 && $tabs_width !== 0) {
-          $indicator.css({"right": calcRightPos($active) });
-          $indicator.css({"left": calcLeftPos($active) });
-        }
-      });
-
-      // Initialize Tabs Content.
-      if (options.swipeable) {
-        // TODO: Duplicate calls with swipeable? handle multiple div wrapping.
-        $links.each(function () {
-          var $curr_content = $(Materialize.escapeHash(this.hash));
-          $curr_content.addClass('carousel-item');
-          $tabs_content = $tabs_content.add($curr_content);
-        });
-        $tabs_wrapper = $tabs_content.wrapAll('<div class="tabs-content carousel"></div>');
-        $tabs_content.css('display', '');
-        $('.tabs-content.carousel').carousel({
-          fullWidth: true,
-          noWrap: true,
-          onCycleTo: function(item) {
-            if (!clicked) {
-              var prev_index = index;
-              index = $tabs_wrapper.index(item);
-              $active = $links.eq(index);
-              animateIndicator(prev_index);
-            }
-          },
-        });
-      } else {
-        // Hide the remaining content
-        $links.not($active).each(function () {
-          $(Materialize.escapeHash(this.hash)).hide();
-        });
-      }
-
-
-      // Bind the click event handler
-      $this.on('click', 'a', function(e) {
-        if ($(this).parent().hasClass('disabled')) {
-          e.preventDefault();
-          return;
-        }
-
-        // Act as regular link if target attribute is specified.
-        if (!!$(this).attr("target")) {
-          return;
-        }
-
-        clicked = true;
-        $tabs_width = $this.width();
-        $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length;
-
-        // Make the old tab inactive.
-        $active.removeClass('active');
-        var $oldContent = $content
-
-        // Update the variables with the new link and content
-        $active = $(this);
-        $content = $(Materialize.escapeHash(this.hash));
-        $links = $this.find('li.tab a');
-        var activeRect = $active.position();
-
-        // Make the tab active.
-        $active.addClass('active');
-        prev_index = index;
-        index = $links.index($(this));
-        if (index < 0) {
-          index = 0;
-        }
-        // Change url to current tab
-        // window.location.hash = $active.attr('href');
-
-        // Swap content
-        if (options.swipeable) {
-          if ($tabs_content.length) {
-            $tabs_content.carousel('set', index);
-          }
-        } else {
-          if ($content !== undefined) {
-            $content.show();
-            $content.addClass('active');
-            if (typeof(options.onShow) === "function") {
-              options.onShow.call(this, $content);
-            }
-          }
-
-          if ($oldContent !== undefined &&
-              !$oldContent.is($content)) {
-            $oldContent.hide();
-            $oldContent.removeClass('active');
-          }
-        }
-
-        // Reset clicked state
-        clickedTimeout = setTimeout(function(){ clicked = false; }, transition);
-
-        // Update indicator
-        animateIndicator(prev_index);
-
-        // Prevent the anchor's default click action
-        e.preventDefault();
-      });
-    });
-
-    },
-    select_tab : function( id ) {
-      this.find('a[href="#' + id + '"]').trigger('click');
-    }
-  };
-
-  $.fn.tabs = function(methodOrOptions) {
-    if ( methods[methodOrOptions] ) {
-      return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
-    } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
-      // Default to "init"
-      return methods.init.apply( this, arguments );
-    } else {
-      $.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.tabs' );
-    }
-  };
-
-  $(document).ready(function(){
-    $('ul.tabs').tabs();
-  });
-}( jQuery ));
-;(function ($) {
-    $.fn.tooltip = function (options) {
-      var timeout = null,
-      margin = 5;
-
-      // Defaults
-      var defaults = {
-        delay: 350,
-        tooltip: '',
-        position: 'bottom',
-        html: false
-      };
-
-      // Remove tooltip from the activator
-      if (options === "remove") {
-        this.each(function() {
-          $('#' + $(this).attr('data-tooltip-id')).remove();
-          $(this).off('mouseenter.tooltip mouseleave.tooltip');
-        });
-        return false;
-      }
-
-      options = $.extend(defaults, options);
-
-      return this.each(function() {
-        var tooltipId = Materialize.guid();
-        var origin = $(this);
-
-        // Destroy old tooltip
-        if (origin.attr('data-tooltip-id')) {
-          $('#' + origin.attr('data-tooltip-id')).remove();
-        }
-
-        origin.attr('data-tooltip-id', tooltipId);
-
-        // Get attributes.
-        var allowHtml,
-            tooltipDelay,
-            tooltipPosition,
-            tooltipText,
-            tooltipEl,
-            backdrop;
-        var setAttributes = function() {
-          allowHtml = origin.attr('data-html') ? origin.attr('data-html') === 'true' : options.html;
-          tooltipDelay = origin.attr('data-delay');
-          tooltipDelay = (tooltipDelay === undefined || tooltipDelay === '') ?
-              options.delay : tooltipDelay;
-          tooltipPosition = origin.attr('data-position');
-          tooltipPosition = (tooltipPosition === undefined || tooltipPosition === '') ?
-              options.position : tooltipPosition;
-          tooltipText = origin.attr('data-tooltip');
-          tooltipText = (tooltipText === undefined || tooltipText === '') ?
-              options.tooltip : tooltipText;
-        };
-        setAttributes();
-
-        var renderTooltipEl = function() {
-          var tooltip = $('<div class="material-tooltip"></div>');
-
-          // Create Text span
-          if (allowHtml) {
-            tooltipText = $('<span></span>').html(tooltipText);
-          } else{
-            tooltipText = $('<span></span>').text(tooltipText);
-          }
-
-          // Create tooltip
-          tooltip.append(tooltipText)
-            .appendTo($('body'))
-            .attr('id', tooltipId);
-
-          // Create backdrop
-          backdrop = $('<div class="backdrop"></div>');
-          backdrop.appendTo(tooltip);
-          return tooltip;
-        };
-        tooltipEl = renderTooltipEl();
-
-        // Destroy previously binded events
-        origin.off('mouseenter.tooltip mouseleave.tooltip');
-        // Mouse In
-        var started = false, timeoutRef;
-        origin.on({'mouseenter.tooltip': function(e) {
-          var showTooltip = function() {
-            setAttributes();
-            started = true;
-            tooltipEl.velocity('stop');
-            backdrop.velocity('stop');
-            tooltipEl.css({ visibility: 'visible', left: '0px', top: '0px' });
-
-            // Tooltip positioning
-            var originWidth = origin.outerWidth();
-            var originHeight = origin.outerHeight();
-            var tooltipHeight = tooltipEl.outerHeight();
-            var tooltipWidth = tooltipEl.outerWidth();
-            var tooltipVerticalMovement = '0px';
-            var tooltipHorizontalMovement = '0px';
-            var backdropOffsetWidth = backdrop[0].offsetWidth;
-            var backdropOffsetHeight = backdrop[0].offsetHeight;
-            var scaleXFactor = 8;
-            var scaleYFactor = 8;
-            var scaleFactor = 0;
-            var targetTop, targetLeft, newCoordinates;
-
-            if (tooltipPosition === "top") {
-              // Top Position
-              targetTop = origin.offset().top - tooltipHeight - margin;
-              targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2;
-              newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight);
-              tooltipVerticalMovement = '-10px';
-              backdrop.css({
-                bottom: 0,
-                left: 0,
-                borderRadius: '14px 14px 0 0',
-                transformOrigin: '50% 100%',
-                marginTop: tooltipHeight,
-                marginLeft: (tooltipWidth/2) - (backdropOffsetWidth/2)
-              });
-            }
-            // Left Position
-            else if (tooltipPosition === "left") {
-              targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2;
-              targetLeft =  origin.offset().left - tooltipWidth - margin;
-              newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight);
-
-              tooltipHorizontalMovement = '-10px';
-              backdrop.css({
-                top: '-7px',
-                right: 0,
-                width: '14px',
-                height: '14px',
-                borderRadius: '14px 0 0 14px',
-                transformOrigin: '95% 50%',
-                marginTop: tooltipHeight/2,
-                marginLeft: tooltipWidth
-              });
-            }
-            // Right Position
-            else if (tooltipPosition === "right") {
-              targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2;
-              targetLeft = origin.offset().left + originWidth + margin;
-              newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight);
-
-              tooltipHorizontalMovement = '+10px';
-              backdrop.css({
-                top: '-7px',
-                left: 0,
-                width: '14px',
-                height: '14px',
-                borderRadius: '0 14px 14px 0',
-                transformOrigin: '5% 50%',
-                marginTop: tooltipHeight/2,
-                marginLeft: '0px'
-              });
-            }
-            else {
-              // Bottom Position
-              targetTop = origin.offset().top + origin.outerHeight() + margin;
-              targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2;
-              newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight);
-              tooltipVerticalMovement = '+10px';
-              backdrop.css({
-                top: 0,
-                left: 0,
-                marginLeft: (tooltipWidth/2) - (backdropOffsetWidth/2)
-              });
-            }
-
-            // Set tooptip css placement
-            tooltipEl.css({
-              top: newCoordinates.y,
-              left: newCoordinates.x
-            });
-
-            // Calculate Scale to fill
-            scaleXFactor = Math.SQRT2 * tooltipWidth / parseInt(backdropOffsetWidth);
-            scaleYFactor = Math.SQRT2 * tooltipHeight / parseInt(backdropOffsetHeight);
-            scaleFactor = Math.max(scaleXFactor, scaleYFactor);
-
-            tooltipEl.velocity({ translateY: tooltipVerticalMovement, translateX: tooltipHorizontalMovement}, { duration: 350, queue: false })
-              .velocity({opacity: 1}, {duration: 300, delay: 50, queue: false});
-            backdrop.css({ visibility: 'visible' })
-              .velocity({opacity:1},{duration: 55, delay: 0, queue: false})
-              .velocity({scaleX: scaleFactor, scaleY: scaleFactor}, {duration: 300, delay: 0, queue: false, easing: 'easeInOutQuad'});
-          };
-
-          timeoutRef = setTimeout(showTooltip, tooltipDelay); // End Interval
-
-        // Mouse Out
-        },
-        'mouseleave.tooltip': function(){
-          // Reset State
-          started = false;
-          clearTimeout(timeoutRef);
-
-          // Animate back
-          setTimeout(function() {
-            if (started !== true) {
-              tooltipEl.velocity({
-                opacity: 0, translateY: 0, translateX: 0}, { duration: 225, queue: false});
-              backdrop.velocity({opacity: 0, scaleX: 1, scaleY: 1}, {
-                duration:225,
-                queue: false,
-                complete: function(){
-                  backdrop.css({ visibility: 'hidden' });
-                  tooltipEl.css({ visibility: 'hidden' });
-                  started = false;}
-              });
-            }
-          },225);
-        }
-        });
-    });
-  };
-
-  var repositionWithinScreen = function(x, y, width, height) {
-    var newX = x;
-    var newY = y;
-
-    if (newX < 0) {
-      newX = 4;
-    } else if (newX + width > window.innerWidth) {
-      newX -= newX + width - window.innerWidth;
-    }
-
-    if (newY < 0) {
-      newY = 4;
-    } else if (newY + height > window.innerHeight + $(window).scrollTop) {
-      newY -= newY + height - window.innerHeight;
-    }
-
-    return {x: newX, y: newY};
-  };
-
-  $(document).ready(function(){
-     $('.tooltipped').tooltip();
-   });
-}( jQuery ));
-;/*!
- * Waves v0.6.4
- * http://fian.my.id/Waves
- *
- * Copyright 2014 Alfiana E. Sibuea and other contributors
- * Released under the MIT license
- * https://github.com/fians/Waves/blob/master/LICENSE
- */
-
-;(function(window) {
-    'use strict';
-
-    var Waves = Waves || {};
-    var $$ = document.querySelectorAll.bind(document);
-
-    // Find exact position of element
-    function isWindow(obj) {
-        return obj !== null && obj === obj.window;
-    }
-
-    function getWindow(elem) {
-        return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
-    }
-
-    function offset(elem) {
-        var docElem, win,
-            box = {top: 0, left: 0},
-            doc = elem && elem.ownerDocument;
-
-        docElem = doc.documentElement;
-
-        if (typeof elem.getBoundingClientRect !== typeof undefined) {
-            box = elem.getBoundingClientRect();
-        }
-        win = getWindow(doc);
-        return {
-            top: box.top + win.pageYOffset - docElem.clientTop,
-            left: box.left + win.pageXOffset - docElem.clientLeft
-        };
-    }
-
-    function convertStyle(obj) {
-        var style = '';
-
-        for (var a in obj) {
-            if (obj.hasOwnProperty(a)) {
-                style += (a + ':' + obj[a] + ';');
-            }
-        }
-
-        return style;
-    }
-
-    var Effect = {
-
-        // Effect delay
-        duration: 750,
-
-        show: function(e, element) {
-
-            // Disable right click
-            if (e.button === 2) {
-                return false;
-            }
-
-            var el = element || this;
-
-            // Create ripple
-            var ripple = document.createElement('div');
-            ripple.className = 'waves-ripple';
-            el.appendChild(ripple);
-
-            // Get click coordinate and element witdh
-            var pos         = offset(el);
-            var relativeY   = (e.pageY - pos.top);
-            var relativeX   = (e.pageX - pos.left);
-            var scale       = 'scale('+((el.clientWidth / 100) * 10)+')';
-
-            // Support for touch devices
-            if ('touches' in e) {
-              relativeY   = (e.touches[0].pageY - pos.top);
-              relativeX   = (e.touches[0].pageX - pos.left);
-            }
-
-            // Attach data to element
-            ripple.setAttribute('data-hold', Date.now());
-            ripple.setAttribute('data-scale', scale);
-            ripple.setAttribute('data-x', relativeX);
-            ripple.setAttribute('data-y', relativeY);
-
-            // Set ripple position
-            var rippleStyle = {
-                'top': relativeY+'px',
-                'left': relativeX+'px'
-            };
-
-            ripple.className = ripple.className + ' waves-notransition';
-            ripple.setAttribute('style', convertStyle(rippleStyle));
-            ripple.className = ripple.className.replace('waves-notransition', '');
-
-            // Scale the ripple
-            rippleStyle['-webkit-transform'] = scale;
-            rippleStyle['-moz-transform'] = scale;
-            rippleStyle['-ms-transform'] = scale;
-            rippleStyle['-o-transform'] = scale;
-            rippleStyle.transform = scale;
-            rippleStyle.opacity   = '1';
-
-            rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms';
-            rippleStyle['-moz-transition-duration']    = Effect.duration + 'ms';
-            rippleStyle['-o-transition-duration']      = Effect.duration + 'ms';
-            rippleStyle['transition-duration']         = Effect.duration + 'ms';
-
-            rippleStyle['-webkit-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
-            rippleStyle['-moz-transition-timing-function']    = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
-            rippleStyle['-o-transition-timing-function']      = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
-            rippleStyle['transition-timing-function']         = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
-
-            ripple.setAttribute('style', convertStyle(rippleStyle));
-        },
-
-        hide: function(e) {
-            TouchHandler.touchup(e);
-
-            var el = this;
-            var width = el.clientWidth * 1.4;
-
-            // Get first ripple
-            var ripple = null;
-            var ripples = el.getElementsByClassName('waves-ripple');
-            if (ripples.length > 0) {
-                ripple = ripples[ripples.length - 1];
-            } else {
-                return false;
-            }
-
-            var relativeX   = ripple.getAttribute('data-x');
-            var relativeY   = ripple.getAttribute('data-y');
-            var scale       = ripple.getAttribute('data-scale');
-
-            // Get delay beetween mousedown and mouse leave
-            var diff = Date.now() - Number(ripple.getAttribute('data-hold'));
-            var delay = 350 - diff;
-
-            if (delay < 0) {
-                delay = 0;
-            }
-
-            // Fade out ripple after delay
-            setTimeout(function() {
-                var style = {
-                    'top': relativeY+'px',
-                    'left': relativeX+'px',
-                    'opacity': '0',
-
-                    // Duration
-                    '-webkit-transition-duration': Effect.duration + 'ms',
-                    '-moz-transition-duration': Effect.duration + 'ms',
-                    '-o-transition-duration': Effect.duration + 'ms',
-                    'transition-duration': Effect.duration + 'ms',
-                    '-webkit-transform': scale,
-                    '-moz-transform': scale,
-                    '-ms-transform': scale,
-                    '-o-transform': scale,
-                    'transform': scale,
-                };
-
-                ripple.setAttribute('style', convertStyle(style));
-
-                setTimeout(function() {
-                    try {
-                        el.removeChild(ripple);
-                    } catch(e) {
-                        return false;
-                    }
-                }, Effect.duration);
-            }, delay);
-        },
-
-        // Little hack to make <input> can perform waves effect
-        wrapInput: function(elements) {
-            for (var a = 0; a < elements.length; a++) {
-                var el = elements[a];
-
-                if (el.tagName.toLowerCase() === 'input') {
-                    var parent = el.parentNode;
-
-                    // If input already have parent just pass through
-                    if (parent.tagName.toLowerCase() === 'i' && parent.className.indexOf('waves-effect') !== -1) {
-                        continue;
-                    }
-
-                    // Put element class and style to the specified parent
-                    var wrapper = document.createElement('i');
-                    wrapper.className = el.className + ' waves-input-wrapper';
-
-                    var elementStyle = el.getAttribute('style');
-
-                    if (!elementStyle) {
-                        elementStyle = '';
-                    }
-
-                    wrapper.setAttribute('style', elementStyle);
-
-                    el.className = 'waves-button-input';
-                    el.removeAttribute('style');
-
-                    // Put element as child
-                    parent.replaceChild(wrapper, el);
-                    wrapper.appendChild(el);
-                }
-            }
-        }
-    };
-
-
-    /**
-     * Disable mousedown event for 500ms during and after touch
-     */
-    var TouchHandler = {
-        /* uses an integer rather than bool so there's no issues with
-         * needing to clear timeouts if another touch event occurred
-         * within the 500ms. Cannot mouseup between touchstart and
-         * touchend, nor in the 500ms after touchend. */
-        touches: 0,
-        allowEvent: function(e) {
-            var allow = true;
-
-            if (e.type === 'touchstart') {
-                TouchHandler.touches += 1; //push
-            } else if (e.type === 'touchend' || e.type === 'touchcancel') {
-                setTimeout(function() {
-                    if (TouchHandler.touches > 0) {
-                        TouchHandler.touches -= 1; //pop after 500ms
-                    }
-                }, 500);
-            } else if (e.type === 'mousedown' && TouchHandler.touches > 0) {
-                allow = false;
-            }
-
-            return allow;
-        },
-        touchup: function(e) {
-            TouchHandler.allowEvent(e);
-        }
-    };
-
-
-    /**
-     * Delegated click handler for .waves-effect element.
-     * returns null when .waves-effect element not in "click tree"
-     */
-    function getWavesEffectElement(e) {
-        if (TouchHandler.allowEvent(e) === false) {
-            return null;
-        }
-
-        var element = null;
-        var target = e.target || e.srcElement;
-
-        while (target.parentElement !== null) {
-            if (!(target instanceof SVGElement) && target.className.indexOf('waves-effect') !== -1) {
-                element = target;
-                break;
-            } else if (target.classList.contains('waves-effect')) {
-                element = target;
-                break;
-            }
-            target = target.parentElement;
-        }
-
-        return element;
-    }
-
-    /**
-     * Bubble the click and show effect if .waves-effect elem was found
-     */
-    function showEffect(e) {
-        var element = getWavesEffectElement(e);
-
-        if (element !== null) {
-            Effect.show(e, element);
-
-            if ('ontouchstart' in window) {
-                element.addEventListener('touchend', Effect.hide, false);
-                element.addEventListener('touchcancel', Effect.hide, false);
-            }
-
-            element.addEventListener('mouseup', Effect.hide, false);
-            element.addEventListener('mouseleave', Effect.hide, false);
-        }
-    }
-
-    Waves.displayEffect = function(options) {
-        options = options || {};
-
-        if ('duration' in options) {
-            Effect.duration = options.duration;
-        }
-
-        //Wrap input inside <i> tag
-        Effect.wrapInput($$('.waves-effect'));
-
-        if ('ontouchstart' in window) {
-            document.body.addEventListener('touchstart', showEffect, false);
-        }
-
-        document.body.addEventListener('mousedown', showEffect, false);
-    };
-
-    /**
-     * Attach Waves to an input element (or any element which doesn't
-     * bubble mouseup/mousedown events).
-     *   Intended to be used with dynamically loaded forms/inputs, or
-     * where the user doesn't want a delegated click handler.
-     */
-    Waves.attach = function(element) {
-        //FUTURE: automatically add waves classes and allow users
-        // to specify them with an options param? Eg. light/classic/button
-        if (element.tagName.toLowerCase() === 'input') {
-            Effect.wrapInput([element]);
-            element = element.parentElement;
-        }
-
-        if ('ontouchstart' in window) {
-            element.addEventListener('touchstart', showEffect, false);
-        }
-
-        element.addEventListener('mousedown', showEffect, false);
-    };
-
-    window.Waves = Waves;
-
-    document.addEventListener('DOMContentLoaded', function() {
-        Waves.displayEffect();
-    }, false);
-
-})(window);
-;Materialize.toast = function (message, displayLength, className, completeCallback) {
-  className = className || "";
-
-  var container = document.getElementById('toast-container');
-
-  // Create toast container if it does not exist
-  if (container === null) {
-    // create notification container
-    container = document.createElement('div');
-    container.id = 'toast-container';
-    document.body.appendChild(container);
-  }
-
-  // Select and append toast
-  var newToast = createToast(message);
-
-  // only append toast if message is not undefined
-  if(message){
-    container.appendChild(newToast);
-  }
-
-  newToast.style.opacity = 0;
-
-  // Animate toast in
-  Vel(newToast, {translateY: '-35px',  opacity: 1 }, {duration: 300,
-    easing: 'easeOutCubic',
-    queue: false});
-
-  // Allows timer to be pause while being panned
-  var timeLeft = displayLength;
-  var counterInterval;
-  if (timeLeft != null)  {
-    counterInterval = setInterval (function(){
-      if (newToast.parentNode === null)
-        window.clearInterval(counterInterval);
-
-      // If toast is not being dragged, decrease its time remaining
-      if (!newToast.classList.contains('panning')) {
-        timeLeft -= 20;
-      }
-
-      if (timeLeft <= 0) {
-        // Animate toast out
-        Vel(newToast, {"opacity": 0, marginTop: '-40px'}, { duration: 375,
-            easing: 'easeOutExpo',
-            queue: false,
-            complete: function(){
-              // Call the optional callback
-              if(typeof(completeCallback) === "function")
-                completeCallback();
-              // Remove toast after it times out
-              this[0].parentNode.removeChild(this[0]);
-            }
-          });
-        window.clearInterval(counterInterval);
-      }
-    }, 20);
-  }
-
-
-
-  function createToast(html) {
-
-    // Create toast
-    var toast = document.createElement('div');
-    toast.classList.add('toast');
-    if (className) {
-      var classes = className.split(' ');
-
-      for (var i = 0, count = classes.length; i < count; i++) {
-        toast.classList.add(classes[i]);
-      }
-    }
-  // If type of parameter is HTML Element
-    if ( typeof HTMLElement === "object" ? html instanceof HTMLElement : html && typeof html === "object" && html !== null && html.nodeType === 1 && typeof html.nodeName==="string"
-) {
-      toast.appendChild(html);
-    }
-    else if (html instanceof jQuery) {
-      // Check if it is jQuery object
-      toast.appendChild(html[0]);
-    }
-    else {
-      // Insert as text;
-      toast.innerHTML = html;
-    }
-    // Bind hammer
-    var hammerHandler = new Hammer(toast, {prevent_default: false});
-    hammerHandler.on('pan', function(e) {
-      var deltaX = e.deltaX;
-      var activationDistance = 80;
-
-      // Change toast state
-      if (!toast.classList.contains('panning')){
-        toast.classList.add('panning');
-      }
-
-      var opacityPercent = 1-Math.abs(deltaX / activationDistance);
-      if (opacityPercent < 0)
-        opacityPercent = 0;
-
-      Vel(toast, {left: deltaX, opacity: opacityPercent }, {duration: 50, queue: false, easing: 'easeOutQuad'});
-
-    });
-
-    hammerHandler.on('panend', function(e) {
-      var deltaX = e.deltaX;
-      var activationDistance = 80;
-
-      // If toast dragged past activation point
-      if (Math.abs(deltaX) > activationDistance) {
-        Vel(toast, {marginTop: '-40px'}, { duration: 375,
-          easing: 'easeOutExpo',
-          queue: false,
-          complete: function(){
-            if(typeof(completeCallback) === "function") {
-              completeCallback();
-            }
-            toast.parentNode.removeChild(toast);
-          }
-        });
-
-      } else {
-        toast.classList.remove('panning');
-        // Put toast back into original position
-        Vel(toast, { left: 0, opacity: 1 }, { duration: 300,
-          easing: 'easeOutExpo',
-          queue: false
-        });
-
-      }
-    });
-
-    return toast;
-  }
-};
-;(function ($) {
-
-  var methods = {
-    init : function(options) {
-      var defaults = {
-        menuWidth: 300,
-        edge: 'left',
-        closeOnClick: false,
-        draggable: true
-      };
-      options = $.extend(defaults, options);
-
-      $(this).each(function(){
-        var $this = $(this);
-        var menuId = $this.attr('data-activates');
-        var menu = $("#"+ menuId);
-
-        // Set to width
-        if (options.menuWidth != 300) {
-          menu.css('width', options.menuWidth);
-        }
-
-        // Add Touch Area
-        var $dragTarget = $('.drag-target[data-sidenav="' + menuId + '"]');
-        if (options.draggable) {
-          // Regenerate dragTarget
-          if ($dragTarget.length) {
-            $dragTarget.remove();
-          }
-
-          $dragTarget = $('<div class="drag-target"></div>').attr('data-sidenav', menuId);
-          $('body').append($dragTarget);
-        } else {
-          $dragTarget = $();
-        }
-
-        if (options.edge == 'left') {
-          menu.css('transform', 'translateX(-100%)');
-          $dragTarget.css({'left': 0}); // Add Touch Area
-        }
-        else {
-          menu.addClass('right-aligned') // Change text-alignment to right
-            .css('transform', 'translateX(100%)');
-          $dragTarget.css({'right': 0}); // Add Touch Area
-        }
-
-        // If fixed sidenav, bring menu out
-        if (menu.hasClass('fixed')) {
-            if (window.innerWidth > 992) {
-              menu.css('transform', 'translateX(0)');
-            }
-          }
-
-        // Window resize to reset on large screens fixed
-        if (menu.hasClass('fixed')) {
-          $(window).resize( function() {
-            if (window.innerWidth > 992) {
-              // Close menu if window is resized bigger than 992 and user has fixed sidenav
-              if ($('#sidenav-overlay').length !== 0 && menuOut) {
-                removeMenu(true);
-              }
-              else {
-                // menu.removeAttr('style');
-                menu.css('transform', 'translateX(0%)');
-                // menu.css('width', options.menuWidth);
-              }
-            }
-            else if (menuOut === false){
-              if (options.edge === 'left') {
-                menu.css('transform', 'translateX(-100%)');
-              } else {
-                menu.css('transform', 'translateX(100%)');
-              }
-
-            }
-
-          });
-        }
-
-        // if closeOnClick, then add close event for all a tags in side sideNav
-        if (options.closeOnClick === true) {
-          menu.on("click.itemclick", "a:not(.collapsible-header)", function(){
-            removeMenu();
-          });
-        }
-
-        var removeMenu = function(restoreNav) {
-          panning = false;
-          menuOut = false;
-          // Reenable scrolling
-          $('body').css({
-            overflow: '',
-            width: ''
-          });
-
-          $('#sidenav-overlay').velocity({opacity: 0}, {duration: 200,
-              queue: false, easing: 'easeOutQuad',
-            complete: function() {
-              $(this).remove();
-            } });
-          if (options.edge === 'left') {
-            // Reset phantom div
-            $dragTarget.css({width: '', right: '', left: '0'});
-            menu.velocity(
-              {'translateX': '-100%'},
-              { duration: 200,
-                queue: false,
-                easing: 'easeOutCubic',
-                complete: function() {
-                  if (restoreNav === true) {
-                    // Restore Fixed sidenav
-                    menu.removeAttr('style');
-                    menu.css('width', options.menuWidth);
-                  }
-                }
-
-            });
-          }
-          else {
-            // Reset phantom div
-            $dragTarget.css({width: '', right: '0', left: ''});
-            menu.velocity(
-              {'translateX': '100%'},
-              { duration: 200,
-                queue: false,
-                easing: 'easeOutCubic',
-                complete: function() {
-                  if (restoreNav === true) {
-                    // Restore Fixed sidenav
-                    menu.removeAttr('style');
-                    menu.css('width', options.menuWidth);
-                  }
-                }
-              });
-          }
-        };
-
-
-
-        // Touch Event
-        var panning = false;
-        var menuOut = false;
-
-        if (options.draggable) {
-          $dragTarget.on('click', function(){
-            if (menuOut) {
-              removeMenu();
-            }
-          });
-
-          $dragTarget.hammer({
-            prevent_default: false
-          }).bind('pan', function(e) {
-
-            if (e.gesture.pointerType == "touch") {
-
-              var direction = e.gesture.direction;
-              var x = e.gesture.center.x;
-              var y = e.gesture.center.y;
-              var velocityX = e.gesture.velocityX;
-
-              // Disable Scrolling
-              var $body = $('body');
-              var $overlay = $('#sidenav-overlay');
-              var oldWidth = $body.innerWidth();
-              $body.css('overflow', 'hidden');
-              $body.width(oldWidth);
-
-              // If overlay does not exist, create one and if it is clicked, close menu
-              if ($overlay.length === 0) {
-                $overlay = $('<div id="sidenav-overlay"></div>');
-                $overlay.css('opacity', 0).click( function(){
-                  removeMenu();
-                });
-                $('body').append($overlay);
-              }
-
-              // Keep within boundaries
-              if (options.edge === 'left') {
-                if (x > options.menuWidth) { x = options.menuWidth; }
-                else if (x < 0) { x = 0; }
-              }
-
-              if (options.edge === 'left') {
-                // Left Direction
-                if (x < (options.menuWidth / 2)) { menuOut = false; }
-                // Right Direction
-                else if (x >= (options.menuWidth / 2)) { menuOut = true; }
-                menu.css('transform', 'translateX(' + (x - options.menuWidth) + 'px)');
-              }
-              else {
-                // Left Direction
-                if (x < (window.innerWidth - options.menuWidth / 2)) {
-                  menuOut = true;
-                }
-                // Right Direction
-                else if (x >= (window.innerWidth - options.menuWidth / 2)) {
-                 menuOut = false;
-               }
-                var rightPos = (x - options.menuWidth / 2);
-                if (rightPos < 0) {
-                  rightPos = 0;
-                }
-
-                menu.css('transform', 'translateX(' + rightPos + 'px)');
-              }
-
-
-              // Percentage overlay
-              var overlayPerc;
-              if (options.edge === 'left') {
-                overlayPerc = x / options.menuWidth;
-                $overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'});
-              }
-              else {
-                overlayPerc = Math.abs((x - window.innerWidth) / options.menuWidth);
-                $overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'});
-              }
-            }
-
-          }).bind('panend', function(e) {
-
-            if (e.gesture.pointerType == "touch") {
-              var $overlay = $('<div id="sidenav-overlay"></div>');
-              var velocityX = e.gesture.velocityX;
-              var x = e.gesture.center.x;
-              var leftPos = x - options.menuWidth;
-              var rightPos = x - options.menuWidth / 2;
-              if (leftPos > 0 ) {
-                leftPos = 0;
-              }
-              if (rightPos < 0) {
-                rightPos = 0;
-              }
-              panning = false;
-
-              if (options.edge === 'left') {
-                // If velocityX <= 0.3 then the user is flinging the menu closed so ignore menuOut
-                if ((menuOut && velocityX <= 0.3) || velocityX < -0.5) {
-                  // Return menu to open
-                  if (leftPos !== 0) {
-                    menu.velocity({'translateX': [0, leftPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'});
-                  }
-
-                  $overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'});
-                  $dragTarget.css({width: '50%', right: 0, left: ''});
-                  menuOut = true;
-                }
-                else if (!menuOut || velocityX > 0.3) {
-                  // Enable Scrolling
-                  $('body').css({
-                    overflow: '',
-                    width: ''
-                  });
-                  // Slide menu closed
-                  menu.velocity({'translateX': [-1 * options.menuWidth - 10, leftPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'});
-                  $overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad',
-                    complete: function () {
-                      $(this).remove();
-                    }});
-                  $dragTarget.css({width: '10px', right: '', left: 0});
-                }
-              }
-              else {
-                if ((menuOut && velocityX >= -0.3) || velocityX > 0.5) {
-                  // Return menu to open
-                  if (rightPos !== 0) {
-                    menu.velocity({'translateX': [0, rightPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'});
-                  }
-
-                  $overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'});
-                  $dragTarget.css({width: '50%', right: '', left: 0});
-                  menuOut = true;
-                }
-                else if (!menuOut || velocityX < -0.3) {
-                  // Enable Scrolling
-                  $('body').css({
-                    overflow: '',
-                    width: ''
-                  });
-
-                  // Slide menu closed
-                  menu.velocity({'translateX': [options.menuWidth + 10, rightPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'});
-                  $overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad',
-                    complete: function () {
-                      $(this).remove();
-                    }});
-                  $dragTarget.css({width: '10px', right: 0, left: ''});
-                }
-              }
-
-            }
-          });
-        }
-
-        $this.off('click.sidenav').on('click.sidenav', function() {
-          if (menuOut === true) {
-            menuOut = false;
-            panning = false;
-            removeMenu();
-          }
-          else {
-
-            // Disable Scrolling
-            var $body = $('body');
-            var $overlay = $('<div id="sidenav-overlay"></div>');
-            var oldWidth = $body.innerWidth();
-            $body.css('overflow', 'hidden');
-            $body.width(oldWidth);
-
-            // Push current drag target on top of DOM tree
-            $('body').append($dragTarget);
-
-            if (options.edge === 'left') {
-              $dragTarget.css({width: '50%', right: 0, left: ''});
-              menu.velocity({'translateX': [0, -1 * options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'});
-            }
-            else {
-              $dragTarget.css({width: '50%', right: '', left: 0});
-              menu.velocity({'translateX': [0, options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'});
-            }
-
-            $overlay.css('opacity', 0)
-            .click(function(){
-              menuOut = false;
-              panning = false;
-              removeMenu();
-              $overlay.velocity({opacity: 0}, {duration: 300, queue: false, easing: 'easeOutQuad',
-                complete: function() {
-                  $(this).remove();
-                } });
-
-            });
-            $('body').append($overlay);
-            $overlay.velocity({opacity: 1}, {duration: 300, queue: false, easing: 'easeOutQuad',
-              complete: function () {
-                menuOut = true;
-                panning = false;
-              }
-            });
-          }
-
-          return false;
-        });
-      });
-
-
-    },
-    destroy: function () {
-      var $overlay = $('#sidenav-overlay');
-      var $dragTarget = $('.drag-target[data-sidenav="' + $(this).attr('data-activates') + '"]');
-      $overlay.trigger('click');
-      $dragTarget.remove();
-      $(this).off('click');
-      $overlay.remove();
-    },
-    show : function() {
-      this.trigger('click');
-    },
-    hide : function() {
-      $('#sidenav-overlay').trigger('click');
-    }
-  };
-
-
-  $.fn.sideNav = function(methodOrOptions) {
-    if ( methods[methodOrOptions] ) {
-      return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
-    } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
-      // Default to "init"
-      return methods.init.apply( this, arguments );
-    } else {
-      $.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.sideNav' );
-    }
-  }; // Plugin end
-}( jQuery ));
-;/**
- * Extend jquery with a scrollspy plugin.
- * This watches the window scroll and fires events when elements are scrolled into viewport.
- *
- * throttle() and getTime() taken from Underscore.js
- * https://github.com/jashkenas/underscore
- *
- * @author Copyright 2013 John Smart
- * @license https://raw.github.com/thesmart/jquery-scrollspy/master/LICENSE
- * @see https://github.com/thesmart
- * @version 0.1.2
- */
-(function($) {
-
-       var jWindow = $(window);
-       var elements = [];
-       var elementsInView = [];
-       var isSpying = false;
-       var ticks = 0;
-       var unique_id = 1;
-       var offset = {
-               top : 0,
-               right : 0,
-               bottom : 0,
-               left : 0,
-       }
-
-       /**
-        * Find elements that are within the boundary
-        * @param {number} top
-        * @param {number} right
-        * @param {number} bottom
-        * @param {number} left
-        * @return {jQuery}             A collection of elements
-        */
-       function findElements(top, right, bottom, left) {
-               var hits = $();
-               $.each(elements, function(i, element) {
-                       if (element.height() > 0) {
-                               var elTop = element.offset().top,
-                                       elLeft = element.offset().left,
-                                       elRight = elLeft + element.width(),
-                                       elBottom = elTop + element.height();
-
-                               var isIntersect = !(elLeft > right ||
-                                       elRight < left ||
-                                       elTop > bottom ||
-                                       elBottom < top);
-
-                               if (isIntersect) {
-                                       hits.push(element);
-                               }
-                       }
-               });
-
-               return hits;
-       }
-
-
-       /**
-        * Called when the user scrolls the window
-        */
-       function onScroll(scrollOffset) {
-               // unique tick id
-               ++ticks;
-
-               // viewport rectangle
-               var top = jWindow.scrollTop(),
-                       left = jWindow.scrollLeft(),
-                       right = left + jWindow.width(),
-                       bottom = top + jWindow.height();
-
-               // determine which elements are in view
-               var intersections = findElements(top+offset.top + scrollOffset || 200, right+offset.right, bottom+offset.bottom, left+offset.left);
-               $.each(intersections, function(i, element) {
-
-                       var lastTick = element.data('scrollSpy:ticks');
-                       if (typeof lastTick != 'number') {
-                               // entered into view
-                               element.triggerHandler('scrollSpy:enter');
-                       }
-
-                       // update tick id
-                       element.data('scrollSpy:ticks', ticks);
-               });
-
-               // determine which elements are no longer in view
-               $.each(elementsInView, function(i, element) {
-                       var lastTick = element.data('scrollSpy:ticks');
-                       if (typeof lastTick == 'number' && lastTick !== ticks) {
-                               // exited from view
-                               element.triggerHandler('scrollSpy:exit');
-                               element.data('scrollSpy:ticks', null);
-                       }
-               });
-
-               // remember elements in view for next tick
-               elementsInView = intersections;
-       }
-
-       /**
-        * Called when window is resized
-       */
-       function onWinSize() {
-               jWindow.trigger('scrollSpy:winSize');
-       }
-
-
-       /**
-        * Enables ScrollSpy using a selector
-        * @param {jQuery|string} selector  The elements collection, or a selector
-        * @param {Object=} options     Optional.
-        throttle : number -> scrollspy throttling. Default: 100 ms
-        offsetTop : number -> offset from top. Default: 0
-        offsetRight : number -> offset from right. Default: 0
-        offsetBottom : number -> offset from bottom. Default: 0
-        offsetLeft : number -> offset from left. Default: 0
-        * @returns {jQuery}
-        */
-       $.scrollSpy = function(selector, options) {
-         var defaults = {
-                       throttle: 100,
-                       scrollOffset: 200 // offset - 200 allows elements near bottom of page to scroll
-    };
-    options = $.extend(defaults, options);
-
-               var visible = [];
-               selector = $(selector);
-               selector.each(function(i, element) {
-                       elements.push($(element));
-                       $(element).data("scrollSpy:id", i);
-                       // Smooth scroll to section
-                 $('a[href="#' + $(element).attr('id') + '"]').click(function(e) {
-                   e.preventDefault();
-                   var offset = $(Materialize.escapeHash(this.hash)).offset().top + 1;
-               $('html, body').animate({ scrollTop: offset - options.scrollOffset }, {duration: 400, queue: false, easing: 'easeOutCubic'});
-                 });
-               });
-
-               offset.top = options.offsetTop || 0;
-               offset.right = options.offsetRight || 0;
-               offset.bottom = options.offsetBottom || 0;
-               offset.left = options.offsetLeft || 0;
-
-               var throttledScroll = Materialize.throttle(function() {
-                       onScroll(options.scrollOffset);
-               }, options.throttle || 100);
-               var readyScroll = function(){
-                       $(document).ready(throttledScroll);
-               };
-
-               if (!isSpying) {
-                       jWindow.on('scroll', readyScroll);
-                       jWindow.on('resize', readyScroll);
-                       isSpying = true;
-               }
-
-               // perform a scan once, after current execution context, and after dom is ready
-               setTimeout(readyScroll, 0);
-
-
-               selector.on('scrollSpy:enter', function() {
-                       visible = $.grep(visible, function(value) {
-             return value.height() != 0;
-           });
-
-                       var $this = $(this);
-
-                       if (visible[0]) {
-                               $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active');
-                               if ($this.data('scrollSpy:id') < visible[0].data('scrollSpy:id')) {
-                                       visible.unshift($(this));
-                               }
-                               else {
-                                       visible.push($(this));
-                               }
-                       }
-                       else {
-                               visible.push($(this));
-                       }
-
-
-                       $('a[href="#' + visible[0].attr('id') + '"]').addClass('active');
-               });
-               selector.on('scrollSpy:exit', function() {
-                       visible = $.grep(visible, function(value) {
-             return value.height() != 0;
-           });
-
-                       if (visible[0]) {
-                               $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active');
-                               var $this = $(this);
-                               visible = $.grep(visible, function(value) {
-               return value.attr('id') != $this.attr('id');
-             });
-             if (visible[0]) { // Check if empty
-                                       $('a[href="#' + visible[0].attr('id') + '"]').addClass('active');
-             }
-                       }
-               });
-
-               return selector;
-       };
-
-       /**
-        * Listen for window resize events
-        * @param {Object=} options                                             Optional. Set { throttle: number } to change throttling. Default: 100 ms
-        * @returns {jQuery}            $(window)
-        */
-       $.winSizeSpy = function(options) {
-               $.winSizeSpy = function() { return jWindow; }; // lock from multiple calls
-               options = options || {
-                       throttle: 100
-               };
-               return jWindow.on('resize', Materialize.throttle(onWinSize, options.throttle || 100));
-       };
-
-       /**
-        * Enables ScrollSpy on a collection of elements
-        * e.g. $('.scrollSpy').scrollSpy()
-        * @param {Object=} options     Optional.
-                                                                                       throttle : number -> scrollspy throttling. Default: 100 ms
-                                                                                       offsetTop : number -> offset from top. Default: 0
-                                                                                       offsetRight : number -> offset from right. Default: 0
-                                                                                       offsetBottom : number -> offset from bottom. Default: 0
-                                                                                       offsetLeft : number -> offset from left. Default: 0
-        * @returns {jQuery}
-        */
-       $.fn.scrollSpy = function(options) {
-               return $.scrollSpy($(this), options);
-       };
-
-})(jQuery);
-;(function ($) {
-  $(document).ready(function() {
-
-    // Function to update labels of text fields
-    Materialize.updateTextFields = function() {
-      var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea';
-      $(input_selector).each(function(index, element) {
-        var $this = $(this);
-        if ($(element).val().length > 0 || element.autofocus || $this.attr('placeholder') !== undefined) {
-          $this.siblings('label').addClass('active');
-        } else if ($(element)[0].validity) {
-          $this.siblings('label').toggleClass('active', $(element)[0].validity.badInput === true);
-        } else {
-          $this.siblings('label').removeClass('active');
-        }
-      });
-    };
-
-    // Text based inputs
-    var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea';
-
-    // Add active if form auto complete
-    $(document).on('change', input_selector, function () {
-      if($(this).val().length !== 0 || $(this).attr('placeholder') !== undefined) {
-        $(this).siblings('label').addClass('active');
-      }
-      validate_field($(this));
-    });
-
-    // Add active if input element has been pre-populated on document ready
-    $(document).ready(function() {
-      Materialize.updateTextFields();
-    });
-
-    // HTML DOM FORM RESET handling
-    $(document).on('reset', function(e) {
-      var formReset = $(e.target);
-      if (formReset.is('form')) {
-        formReset.find(input_selector).removeClass('valid').removeClass('invalid');
-        formReset.find(input_selector).each(function () {
-          if ($(this).attr('value') === '') {
-            $(this).siblings('label').removeClass('active');
-          }
-        });
-
-        // Reset select
-        formReset.find('select.initialized').each(function () {
-          var reset_text = formReset.find('option[selected]').text();
-          formReset.siblings('input.select-dropdown').val(reset_text);
-        });
-      }
-    });
-
-    // Add active when element has focus
-    $(document).on('focus', input_selector, function () {
-      $(this).siblings('label, .prefix').addClass('active');
-    });
-
-    $(document).on('blur', input_selector, function () {
-      var $inputElement = $(this);
-      var selector = ".prefix";
-
-      if ($inputElement.val().length === 0 && $inputElement[0].validity.badInput !== true && $inputElement.attr('placeholder') === undefined) {
-        selector += ", label";
-      }
-
-      $inputElement.siblings(selector).removeClass('active');
-
-      validate_field($inputElement);
-    });
-
-    window.validate_field = function(object) {
-      var hasLength = object.attr('data-length') !== undefined;
-      var lenAttr = parseInt(object.attr('data-length'));
-      var len = object.val().length;
-
-      if (object.val().length === 0 && object[0].validity.badInput === false) {
-        if (object.hasClass('validate')) {
-          object.removeClass('valid');
-          object.removeClass('invalid');
-        }
-      }
-      else {
-        if (object.hasClass('validate')) {
-          // Check for character counter attributes
-          if ((object.is(':valid') && hasLength && (len <= lenAttr)) || (object.is(':valid') && !hasLength)) {
-            object.removeClass('invalid');
-            object.addClass('valid');
-          }
-          else {
-            object.removeClass('valid');
-            object.addClass('invalid');
-          }
-        }
-      }
-    };
-
-    // Radio and Checkbox focus class
-    var radio_checkbox = 'input[type=radio], input[type=checkbox]';
-    $(document).on('keyup.radio', radio_checkbox, function(e) {
-      // TAB, check if tabbing to radio or checkbox.
-      if (e.which === 9) {
-        $(this).addClass('tabbed');
-        var $this = $(this);
-        $this.one('blur', function(e) {
-
-          $(this).removeClass('tabbed');
-        });
-        return;
-      }
-    });
-
-    // Textarea Auto Resize
-    var hiddenDiv = $('.hiddendiv').first();
-    if (!hiddenDiv.length) {
-      hiddenDiv = $('<div class="hiddendiv common"></div>');
-      $('body').append(hiddenDiv);
-    }
-    var text_area_selector = '.materialize-textarea';
-
-    function textareaAutoResize($textarea) {
-      // Set font properties of hiddenDiv
-
-      var fontFamily = $textarea.css('font-family');
-      var fontSize = $textarea.css('font-size');
-      var lineHeight = $textarea.css('line-height');
-
-      if (fontSize) { hiddenDiv.css('font-size', fontSize); }
-      if (fontFamily) { hiddenDiv.css('font-family', fontFamily); }
-      if (lineHeight) { hiddenDiv.css('line-height', lineHeight); }
-
-      if ($textarea.attr('wrap') === "off") {
-        hiddenDiv.css('overflow-wrap', "normal")
-                 .css('white-space', "pre");
-      }
-
-      hiddenDiv.text($textarea.val() + '\n');
-      var content = hiddenDiv.html().replace(/\n/g, '<br>');
-      hiddenDiv.html(content);
-
-
-      // When textarea is hidden, width goes crazy.
-      // Approximate with half of window size
-
-      if ($textarea.is(':visible')) {
-        hiddenDiv.css('width', $textarea.width());
-      }
-      else {
-        hiddenDiv.css('width', $(window).width()/2);
-      }
-
-      $textarea.css('height', hiddenDiv.height());
-    }
-
-    $(text_area_selector).each(function () {
-      var $textarea = $(this);
-      if ($textarea.val().length) {
-        textareaAutoResize($textarea);
-      }
-    });
-
-    $('body').on('keyup keydown autoresize', text_area_selector, function () {
-      textareaAutoResize($(this));
-    });
-
-    // File Input Path
-    $(document).on('change', '.file-field input[type="file"]', function () {
-      var file_field = $(this).closest('.file-field');
-      var path_input = file_field.find('input.file-path');
-      var files      = $(this)[0].files;
-      var file_names = [];
-      for (var i = 0; i < files.length; i++) {
-        file_names.push(files[i].name);
-      }
-      path_input.val(file_names.join(", "));
-      path_input.trigger('change');
-    });
-
-    /****************
-    *  Range Input  *
-    ****************/
-
-    var range_type = 'input[type=range]';
-    var range_mousedown = false;
-    var left;
-
-    $(range_type).each(function () {
-      var thumb = $('<span class="thumb"><span class="value"></span></span>');
-      $(this).after(thumb);
-    });
-
-    var range_wrapper = '.range-field';
-    $(document).on('change', range_type, function(e) {
-      var thumb = $(this).siblings('.thumb');
-      thumb.find('.value').html($(this).val());
-    });
-
-    $(document).on('input mousedown touchstart', range_type, function(e) {
-      var thumb = $(this).siblings('.thumb');
-      var width = $(this).outerWidth();
-
-      // If thumb indicator does not exist yet, create it
-      if (thumb.length <= 0) {
-        thumb = $('<span class="thumb"><span class="value"></span></span>');
-        $(this).after(thumb);
-      }
-
-      // Set indicator value
-      thumb.find('.value').html($(this).val());
-
-      range_mousedown = true;
-      $(this).addClass('active');
-
-      if (!thumb.hasClass('active')) {
-        thumb.velocity({ height: "30px", width: "30px", top: "-20px", marginLeft: "-15px"}, { duration: 300, easing: 'easeOutExpo' });
-      }
-
-      if (e.type !== 'input') {
-        if(e.pageX === undefined || e.pageX === null){//mobile
-           left = e.originalEvent.touches[0].pageX - $(this).offset().left;
-        }
-        else{ // desktop
-           left = e.pageX - $(this).offset().left;
-        }
-        if (left < 0) {
-          left = 0;
-        }
-        else if (left > width) {
-          left = width;
-        }
-        thumb.addClass('active').css('left', left);
-      }
-
-      thumb.find('.value').html($(this).val());
-    });
-
-    $(document).on('mouseup touchend', range_wrapper, function() {
-      range_mousedown = false;
-      $(this).removeClass('active');
-    });
-
-    $(document).on('mousemove touchmove', range_wrapper, function(e) {
-      var thumb = $(this).children('.thumb');
-      var left;
-      if (range_mousedown) {
-        if (!thumb.hasClass('active')) {
-          thumb.velocity({ height: '30px', width: '30px', top: '-20px', marginLeft: '-15px'}, { duration: 300, easing: 'easeOutExpo' });
-        }
-        if (e.pageX === undefined || e.pageX === null) { //mobile
-          left = e.originalEvent.touches[0].pageX - $(this).offset().left;
-        }
-        else{ // desktop
-          left = e.pageX - $(this).offset().left;
-        }
-        var width = $(this).outerWidth();
-
-        if (left < 0) {
-          left = 0;
-        }
-        else if (left > width) {
-          left = width;
-        }
-        thumb.addClass('active').css('left', left);
-        thumb.find('.value').html(thumb.siblings(range_type).val());
-      }
-    });
-
-    $(document).on('mouseout touchleave', range_wrapper, function() {
-      if (!range_mousedown) {
-
-        var thumb = $(this).children('.thumb');
-
-        if (thumb.hasClass('active')) {
-          thumb.velocity({ height: '0', width: '0', top: '10px', marginLeft: '-6px'}, { duration: 100 });
-        }
-        thumb.removeClass('active');
-      }
-    });
-
-    /**************************
-     * Auto complete plugin  *
-     *************************/
-    $.fn.autocomplete = function (options) {
-      // Defaults
-      var defaults = {
-        data: {},
-        limit: Infinity,
-        onAutocomplete: null
-      };
-
-      options = $.extend(defaults, options);
-
-      return this.each(function() {
-        var $input = $(this);
-        var data = options.data,
-            count = 0,
-            activeIndex = 0,
-            oldVal,
-            $inputDiv = $input.closest('.input-field'); // Div to append on
-
-        // Check if data isn't empty
-        if (!$.isEmptyObject(data)) {
-          var $autocomplete = $('<ul class="autocomplete-content dropdown-content"></ul>');
-          var $oldAutocomplete;
-
-          // Append autocomplete element.
-          // Prevent double structure init.
-          if ($inputDiv.length) {
-            $oldAutocomplete = $inputDiv.children('.autocomplete-content.dropdown-content').first();
-            if (!$oldAutocomplete.length) {
-              $inputDiv.append($autocomplete); // Set ul in body
-            }
-          } else {
-            $oldAutocomplete = $input.next('.autocomplete-content.dropdown-content');
-            if (!$oldAutocomplete.length) {
-              $input.after($autocomplete);
-            }
-          }
-          if ($oldAutocomplete.length) {
-            $autocomplete = $oldAutocomplete;
-          }
-
-          // Highlight partial match.
-          var highlight = function(string, $el) {
-            var img = $el.find('img');
-            var matchStart = $el.text().toLowerCase().indexOf("" + string.toLowerCase() + ""),
-                matchEnd = matchStart + string.length - 1,
-                beforeMatch = $el.text().slice(0, matchStart),
-                matchText = $el.text().slice(matchStart, matchEnd + 1),
-                afterMatch = $el.text().slice(matchEnd + 1);
-            $el.html("<span>" + beforeMatch + "<span class='highlight'>" + matchText + "</span>" + afterMatch + "</span>");
-            if (img.length) {
-              $el.prepend(img);
-            }
-          };
-
-          // Reset current element position
-          var resetCurrentElement = function() {
-            activeIndex = 0;
-            $autocomplete.find('.active').removeClass('active');
-          }
-
-          // Perform search
-          $input.off('keyup.autocomplete').on('keyup.autocomplete', function (e) {
-            // Reset count.
-            count = 0;
-
-            // Don't capture enter or arrow key usage.
-            if (e.which === 13 ||
-                e.which === 38 ||
-                e.which === 40) {
-              return;
-            }
-
-            var val = $input.val().toLowerCase();
-
-            // Check if the input isn't empty
-            if (oldVal !== val) {
-              $autocomplete.empty();
-              resetCurrentElement();
-
-              if (val !== '') {
-                for(var key in data) {
-                  if (data.hasOwnProperty(key) &&
-                      key.toLowerCase().indexOf(val) !== -1 &&
-                      key.toLowerCase() !== val) {
-                    // Break if past limit
-                    if (count >= options.limit) {
-                      break;
-                    }
-
-                    var autocompleteOption = $('<li></li>');
-                    if (!!data[key]) {
-                      autocompleteOption.append('<img src="'+ data[key] +'" class="right circle"><span>'+ key +'</span>');
-                    } else {
-                      autocompleteOption.append('<span>'+ key +'</span>');
-                    }
-
-                    $autocomplete.append(autocompleteOption);
-                    highlight(val, autocompleteOption);
-                    count++;
-                  }
-                }
-              }
-            }
-
-            // Update oldVal
-            oldVal = val;
-          });
-
-          $input.off('keydown.autocomplete').on('keydown.autocomplete', function (e) {
-            // Arrow keys and enter key usage
-            var keyCode = e.which,
-                liElement,
-                numItems = $autocomplete.children('li').length,
-                $active = $autocomplete.children('.active').first();
-
-            // select element on Enter
-            if (keyCode === 13) {
-              liElement = $autocomplete.children('li').eq(activeIndex);
-              if (liElement.length) {
-                liElement.click();
-                e.preventDefault();
-              }
-              return;
-            }
-
-            // Capture up and down key
-            if ( keyCode === 38 || keyCode === 40 ) {
-              e.preventDefault();
-
-              if (keyCode === 38 &&
-                  activeIndex > 0) {
-                activeIndex--;
-              }
-
-              if (keyCode === 40 &&
-                  activeIndex < (numItems - 1) &&
-                  $active.length) {
-                activeIndex++;
-              }
-
-              $active.removeClass('active');
-              $autocomplete.children('li').eq(activeIndex).addClass('active');
-            }
-          });
-
-          // Set input value
-          $autocomplete.on('click', 'li', function () {
-            var text = $(this).text().trim();
-            $input.val(text);
-            $input.trigger('change');
-            $autocomplete.empty();
-            resetCurrentElement();
-
-            // Handle onAutocomplete callback.
-            if (typeof(options.onAutocomplete) === "function") {
-              options.onAutocomplete.call(this, text);
-            }
-          });
-        }
-      });
-    };
-
-  }); // End of $(document).ready
-
-  /*******************
-   *  Select Plugin  *
-   ******************/
-  $.fn.material_select = function (callback) {
-    $(this).each(function(){
-      var $select = $(this);
-
-      if ($select.hasClass('browser-default')) {
-        return; // Continue to next (return false breaks out of entire loop)
-      }
-
-      var multiple = $select.attr('multiple') ? true : false,
-          lastID = $select.data('select-id'); // Tear down structure if Select needs to be rebuilt
-
-      if (lastID) {
-        $select.parent().find('span.caret').remove();
-        $select.parent().find('input').remove();
-
-        $select.unwrap();
-        $('ul#select-options-'+lastID).remove();
-      }
-
-      // If destroying the select, remove the selelct-id and reset it to it's uninitialized state.
-      if(callback === 'destroy') {
-        $select.data('select-id', null).removeClass('initialized');
-        return;
-      }
-
-      var uniqueID = Materialize.guid();
-      $select.data('select-id', uniqueID);
-      var wrapper = $('<div class="select-wrapper"></div>');
-      wrapper.addClass($select.attr('class'));
-      var options = $('<ul id="select-options-' + uniqueID +'" class="dropdown-content select-dropdown ' + (multiple ? 'multiple-select-dropdown' : '') + '"></ul>'),
-          selectChildren = $select.children('option, optgroup'),
-          valuesSelected = [],
-          optionsHover = false;
-
-      var label = $select.find('option:selected').html() || $select.find('option:first').html() || "";
-
-      // Function that renders and appends the option taking into
-      // account type and possible image icon.
-      var appendOptionWithIcon = function(select, option, type) {
-        // Add disabled attr if disabled
-        var disabledClass = (option.is(':disabled')) ? 'disabled ' : '';
-        var optgroupClass = (type === 'optgroup-option') ? 'optgroup-option ' : '';
-
-        // add icons
-        var icon_url = option.data('icon');
-        var classes = option.attr('class');
-        if (!!icon_url) {
-          var classString = '';
-          if (!!classes) classString = ' class="' + classes + '"';
-
-          // Check for multiple type.
-          if (type === 'multiple') {
-            options.append($('<li class="' + disabledClass + '"><img alt="" src="' + icon_url + '"' + classString + '><span><input type="checkbox"' + disabledClass + '/><label></label>' + option.html() + '</span></li>'));
-          } else {
-            options.append($('<li class="' + disabledClass + optgroupClass + '"><img alt="" src="' + icon_url + '"' + classString + '><span>' + option.html() + '</span></li>'));
-          }
-          return true;
-        }
-
-        // Check for multiple type.
-        if (type === 'multiple') {
-          options.append($('<li class="' + disabledClass + '"><span><input type="checkbox"' + disabledClass + '/><label></label>' + option.html() + '</span></li>'));
-        } else {
-          options.append($('<li class="' + disabledClass + optgroupClass + '"><span>' + option.html() + '</span></li>'));
-        }
-      };
-
-      /* Create dropdown structure. */
-      if (selectChildren.length) {
-        selectChildren.each(function() {
-          if ($(this).is('option')) {
-            // Direct descendant option.
-            if (multiple) {
-              appendOptionWithIcon($select, $(this), 'multiple');
-
-            } else {
-              appendOptionWithIcon($select, $(this));
-            }
-          } else if ($(this).is('optgroup')) {
-            // Optgroup.
-            var selectOptions = $(this).children('option');
-            options.append($('<li class="optgroup"><span>' + $(this).attr('label') + '</span></li>'));
-
-            selectOptions.each(function() {
-              appendOptionWithIcon($select, $(this), 'optgroup-option');
-            });
-          }
-        });
-      }
-
-      options.find('li:not(.optgroup)').each(function (i) {
-        $(this).click(function (e) {
-          // Check if option element is disabled
-          if (!$(this).hasClass('disabled') && !$(this).hasClass('optgroup')) {
-            var selected = true;
-
-            if (multiple) {
-              $('input[type="checkbox"]', this).prop('checked', function(i, v) { return !v; });
-              selected = toggleEntryFromArray(valuesSelected, $(this).index(), $select);
-              $newSelect.trigger('focus');
-            } else {
-              options.find('li').removeClass('active');
-              $(this).toggleClass('active');
-              $newSelect.val($(this).text());
-            }
-
-            activateOption(options, $(this));
-            $select.find('option').eq(i).prop('selected', selected);
-            // Trigger onchange() event
-            $select.trigger('change');
-            if (typeof callback !== 'undefined') callback();
-          }
-
-          e.stopPropagation();
-        });
-      });
-
-      // Wrap Elements
-      $select.wrap(wrapper);
-      // Add Select Display Element
-      var dropdownIcon = $('<span class="caret">&#9660;</span>');
-      if ($select.is(':disabled'))
-        dropdownIcon.addClass('disabled');
-
-      // escape double quotes
-      var sanitizedLabelHtml = label.replace(/"/g, '&quot;');
-
-      var $newSelect = $('<input type="text" class="select-dropdown" readonly="true" ' + (($select.is(':disabled')) ? 'disabled' : '') + ' data-activates="select-options-' + uniqueID +'" value="'+ sanitizedLabelHtml +'"/>');
-      $select.before($newSelect);
-      $newSelect.before(dropdownIcon);
-
-      $newSelect.after(options);
-      // Check if section element is disabled
-      if (!$select.is(':disabled')) {
-        $newSelect.dropdown({'hover': false, 'closeOnClick': false});
-      }
-
-      // Copy tabindex
-      if ($select.attr('tabindex')) {
-        $($newSelect[0]).attr('tabindex', $select.attr('tabindex'));
-      }
-
-      $select.addClass('initialized');
-
-      $newSelect.on({
-        'focus': function (){
-          if ($('ul.select-dropdown').not(options[0]).is(':visible')) {
-            $('input.select-dropdown').trigger('close');
-          }
-          if (!options.is(':visible')) {
-            $(this).trigger('open', ['focus']);
-            var label = $(this).val();
-            if (multiple && label.indexOf(',') >= 0) {
-              label = label.split(',')[0];
-            }
-
-            var selectedOption = options.find('li').filter(function() {
-              return $(this).text().toLowerCase() === label.toLowerCase();
-            })[0];
-            activateOption(options, selectedOption, true);
-          }
-        },
-        'click': function (e){
-          e.stopPropagation();
-        }
-      });
-
-      $newSelect.on('blur', function() {
-        if (!multiple) {
-          $(this).trigger('close');
-        }
-        options.find('li.selected').removeClass('selected');
-      });
-
-      options.hover(function() {
-        optionsHover = true;
-      }, function () {
-        optionsHover = false;
-      });
-
-      $(window).on({
-        'click': function () {
-          multiple && (optionsHover || $newSelect.trigger('close'));
-        }
-      });
-
-      // Add initial multiple selections.
-      if (multiple) {
-        $select.find("option:selected:not(:disabled)").each(function () {
-          var index = $(this).index();
-
-          toggleEntryFromArray(valuesSelected, index, $select);
-          options.find("li").eq(index).find(":checkbox").prop("checked", true);
-        });
-      }
-
-      /**
-       * Make option as selected and scroll to selected position
-       * @param {jQuery} collection  Select options jQuery element
-       * @param {Element} newOption  element of the new option
-       * @param {Boolean} firstActivation  If on first activation of select
-       */
-      var activateOption = function(collection, newOption, firstActivation) {
-        if (newOption) {
-          collection.find('li.selected').removeClass('selected');
-          var option = $(newOption);
-          option.addClass('selected');
-          if (!multiple || !!firstActivation) {
-            options.scrollTo(option);
-          }
-        }
-      };
-
-      // Allow user to search by typing
-      // this array is cleared after 1 second
-      var filterQuery = [],
-          onKeyDown = function(e){
-            // TAB - switch to another input
-            if(e.which == 9){
-              $newSelect.trigger('close');
-              return;
-            }
-
-            // ARROW DOWN WHEN SELECT IS CLOSED - open select options
-            if(e.which == 40 && !options.is(':visible')){
-              $newSelect.trigger('open');
-              return;
-            }
-
-            // ENTER WHEN SELECT IS CLOSED - submit form
-            if(e.which == 13 && !options.is(':visible')){
-              return;
-            }
-
-            e.preventDefault();
-
-            // CASE WHEN USER TYPE LETTERS
-            var letter = String.fromCharCode(e.which).toLowerCase(),
-                nonLetters = [9,13,27,38,40];
-            if (letter && (nonLetters.indexOf(e.which) === -1)) {
-              filterQuery.push(letter);
-
-              var string = filterQuery.join(''),
-                  newOption = options.find('li').filter(function() {
-                    return $(this).text().toLowerCase().indexOf(string) === 0;
-                  })[0];
-
-              if (newOption) {
-                activateOption(options, newOption);
-              }
-            }
-
-            // ENTER - select option and close when select options are opened
-            if (e.which == 13) {
-              var activeOption = options.find('li.selected:not(.disabled)')[0];
-              if(activeOption){
-                $(activeOption).trigger('click');
-                if (!multiple) {
-                  $newSelect.trigger('close');
-                }
-              }
-            }
-
-            // ARROW DOWN - move to next not disabled option
-            if (e.which == 40) {
-              if (options.find('li.selected').length) {
-                newOption = options.find('li.selected').next('li:not(.disabled)')[0];
-              } else {
-                newOption = options.find('li:not(.disabled)')[0];
-              }
-              activateOption(options, newOption);
-            }
-
-            // ESC - close options
-            if (e.which == 27) {
-              $newSelect.trigger('close');
-            }
-
-            // ARROW UP - move to previous not disabled option
-            if (e.which == 38) {
-              newOption = options.find('li.selected').prev('li:not(.disabled)')[0];
-              if(newOption)
-                activateOption(options, newOption);
-            }
-
-            // Automaticaly clean filter query so user can search again by starting letters
-            setTimeout(function(){ filterQuery = []; }, 1000);
-          };
-
-      $newSelect.on('keydown', onKeyDown);
-    });
-
-    function toggleEntryFromArray(entriesArray, entryIndex, select) {
-      var index = entriesArray.indexOf(entryIndex),
-          notAdded = index === -1;
-
-      if (notAdded) {
-        entriesArray.push(entryIndex);
-      } else {
-        entriesArray.splice(index, 1);
-      }
-
-      select.siblings('ul.dropdown-content').find('li').eq(entryIndex).toggleClass('active');
-
-      // use notAdded instead of true (to detect if the option is selected or not)
-      select.find('option').eq(entryIndex).prop('selected', notAdded);
-      setValueToInput(entriesArray, select);
-
-      return notAdded;
-    }
-
-    function setValueToInput(entriesArray, select) {
-      var value = '';
-
-      for (var i = 0, count = entriesArray.length; i < count; i++) {
-        var text = select.find('option').eq(entriesArray[i]).text();
-
-        i === 0 ? value += text : value += ', ' + text;
-      }
-
-      if (value === '') {
-        value = select.find('option:disabled').eq(0).text();
-      }
-
-      select.siblings('input.select-dropdown').val(value);
-    }
-  };
-
-}( jQuery ));
-;(function ($) {
-
-  var methods = {
-
-    init : function(options) {
-      var defaults = {
-        indicators: true,
-        height: 400,
-        transition: 500,
-        interval: 6000
-      };
-      options = $.extend(defaults, options);
-
-      return this.each(function() {
-
-        // For each slider, we want to keep track of
-        // which slide is active and its associated content
-        var $this = $(this);
-        var $slider = $this.find('ul.slides').first();
-        var $slides = $slider.find('> li');
-        var $active_index = $slider.find('.active').index();
-        var $active, $indicators, $interval;
-        if ($active_index != -1) { $active = $slides.eq($active_index); }
-
-        // Transitions the caption depending on alignment
-        function captionTransition(caption, duration) {
-          if (caption.hasClass("center-align")) {
-            caption.velocity({opacity: 0, translateY: -100}, {duration: duration, queue: false});
-          }
-          else if (caption.hasClass("right-align")) {
-            caption.velocity({opacity: 0, translateX: 100}, {duration: duration, queue: false});
-          }
-          else if (caption.hasClass("left-align")) {
-            caption.velocity({opacity: 0, translateX: -100}, {duration: duration, queue: false});
-          }
-        }
-
-        // This function will transition the slide to any index of the next slide
-        function moveToSlide(index) {
-          // Wrap around indices.
-          if (index >= $slides.length) index = 0;
-          else if (index < 0) index = $slides.length -1;
-
-          $active_index = $slider.find('.active').index();
-
-          // Only do if index changes
-          if ($active_index != index) {
-            $active = $slides.eq($active_index);
-            $caption = $active.find('.caption');
-
-            $active.removeClass('active');
-            $active.velocity({opacity: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad',
-                              complete: function() {
-                                $slides.not('.active').velocity({opacity: 0, translateX: 0, translateY: 0}, {duration: 0, queue: false});
-                              } });
-            captionTransition($caption, options.transition);
-
-
-            // Update indicators
-            if (options.indicators) {
-              $indicators.eq($active_index).removeClass('active');
-            }
-
-            $slides.eq(index).velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'});
-            $slides.eq(index).find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, delay: options.transition, queue: false, easing: 'easeOutQuad'});
-            $slides.eq(index).addClass('active');
-
-
-            // Update indicators
-            if (options.indicators) {
-              $indicators.eq(index).addClass('active');
-            }
-          }
-        }
-
-        // Set height of slider
-        // If fullscreen, do nothing
-        if (!$this.hasClass('fullscreen')) {
-          if (options.indicators) {
-            // Add height if indicators are present
-            $this.height(options.height + 40);
-          }
-          else {
-            $this.height(options.height);
-          }
-          $slider.height(options.height);
-        }
-
-
-        // Set initial positions of captions
-        $slides.find('.caption').each(function () {
-          captionTransition($(this), 0);
-        });
-
-        // Move img src into background-image
-        $slides.find('img').each(function () {
-          var placeholderBase64 = 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
-          if ($(this).attr('src') !== placeholderBase64) {
-            $(this).css('background-image', 'url(' + $(this).attr('src') + ')' );
-            $(this).attr('src', placeholderBase64);
-          }
-        });
-
-        // dynamically add indicators
-        if (options.indicators) {
-          $indicators = $('<ul class="indicators"></ul>');
-          $slides.each(function( index ) {
-            var $indicator = $('<li class="indicator-item"></li>');
-
-            // Handle clicks on indicators
-            $indicator.click(function () {
-              var $parent = $slider.parent();
-              var curr_index = $parent.find($(this)).index();
-              moveToSlide(curr_index);
-
-              // reset interval
-              clearInterval($interval);
-              $interval = setInterval(
-                function(){
-                  $active_index = $slider.find('.active').index();
-                  if ($slides.length == $active_index + 1) $active_index = 0; // loop to start
-                  else $active_index += 1;
-
-                  moveToSlide($active_index);
-
-                }, options.transition + options.interval
-              );
-            });
-            $indicators.append($indicator);
-          });
-          $this.append($indicators);
-          $indicators = $this.find('ul.indicators').find('li.indicator-item');
-        }
-
-        if ($active) {
-          $active.show();
-        }
-        else {
-          $slides.first().addClass('active').velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'});
-
-          $active_index = 0;
-          $active = $slides.eq($active_index);
-
-          // Update indicators
-          if (options.indicators) {
-            $indicators.eq($active_index).addClass('active');
-          }
-        }
-
-        // Adjust height to current slide
-        $active.find('img').each(function() {
-          $active.find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad'});
-        });
-
-        // auto scroll
-        $interval = setInterval(
-          function(){
-            $active_index = $slider.find('.active').index();
-            moveToSlide($active_index + 1);
-
-          }, options.transition + options.interval
-        );
-
-
-        // HammerJS, Swipe navigation
-
-        // Touch Event
-        var panning = false;
-        var swipeLeft = false;
-        var swipeRight = false;
-
-        $this.hammer({
-            prevent_default: false
-        }).bind('pan', function(e) {
-          if (e.gesture.pointerType === "touch") {
-
-            // reset interval
-            clearInterval($interval);
-
-            var direction = e.gesture.direction;
-            var x = e.gesture.deltaX;
-            var velocityX = e.gesture.velocityX;
-            var velocityY = e.gesture.velocityY;
-
-            $curr_slide = $slider.find('.active');
-            if (Math.abs(velocityX) > Math.abs(velocityY)) {
-              $curr_slide.velocity({ translateX: x
-                  }, {duration: 50, queue: false, easing: 'easeOutQuad'});
-            }
-
-            // Swipe Left
-            if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.65)) {
-              swipeRight = true;
-            }
-            // Swipe Right
-            else if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.65)) {
-              swipeLeft = true;
-            }
-
-            // Make Slide Behind active slide visible
-            var next_slide;
-            if (swipeLeft) {
-              next_slide = $curr_slide.next();
-              if (next_slide.length === 0) {
-                next_slide = $slides.first();
-              }
-              next_slide.velocity({ opacity: 1
-                  }, {duration: 300, queue: false, easing: 'easeOutQuad'});
-            }
-            if (swipeRight) {
-              next_slide = $curr_slide.prev();
-              if (next_slide.length === 0) {
-                next_slide = $slides.last();
-              }
-              next_slide.velocity({ opacity: 1
-                  }, {duration: 300, queue: false, easing: 'easeOutQuad'});
-            }
-
-
-          }
-
-        }).bind('panend', function(e) {
-          if (e.gesture.pointerType === "touch") {
-
-            $curr_slide = $slider.find('.active');
-            panning = false;
-            curr_index = $slider.find('.active').index();
-
-            if (!swipeRight && !swipeLeft || $slides.length <=1) {
-              // Return to original spot
-              $curr_slide.velocity({ translateX: 0
-                  }, {duration: 300, queue: false, easing: 'easeOutQuad'});
-            }
-            else if (swipeLeft) {
-              moveToSlide(curr_index + 1);
-              $curr_slide.velocity({translateX: -1 * $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad',
-                                    complete: function() {
-                                      $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false});
-                                    } });
-            }
-            else if (swipeRight) {
-              moveToSlide(curr_index - 1);
-              $curr_slide.velocity({translateX: $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad',
-                                    complete: function() {
-                                      $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false});
-                                    } });
-            }
-            swipeLeft = false;
-            swipeRight = false;
-
-            // Restart interval
-            clearInterval($interval);
-            $interval = setInterval(
-              function(){
-                $active_index = $slider.find('.active').index();
-                if ($slides.length == $active_index + 1) $active_index = 0; // loop to start
-                else $active_index += 1;
-
-                moveToSlide($active_index);
-
-              }, options.transition + options.interval
-            );
-          }
-        });
-
-        $this.on('sliderPause', function() {
-          clearInterval($interval);
-        });
-
-        $this.on('sliderStart', function() {
-          clearInterval($interval);
-          $interval = setInterval(
-            function(){
-              $active_index = $slider.find('.active').index();
-              if ($slides.length == $active_index + 1) $active_index = 0; // loop to start
-              else $active_index += 1;
-
-              moveToSlide($active_index);
-
-            }, options.transition + options.interval
-          );
-        });
-
-        $this.on('sliderNext', function() {
-          $active_index = $slider.find('.active').index();
-          moveToSlide($active_index + 1);
-        });
-
-        $this.on('sliderPrev', function() {
-          $active_index = $slider.find('.active').index();
-          moveToSlide($active_index - 1);
-        });
-
-      });
-
-
-
-    },
-    pause : function() {
-      $(this).trigger('sliderPause');
-    },
-    start : function() {
-      $(this).trigger('sliderStart');
-    },
-    next : function() {
-      $(this).trigger('sliderNext');
-    },
-    prev : function() {
-      $(this).trigger('sliderPrev');
-    }
-  };
-
-
-  $.fn.slider = function(methodOrOptions) {
-    if ( methods[methodOrOptions] ) {
-      return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
-    } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
-      // Default to "init"
-      return methods.init.apply( this, arguments );
-    } else {
-      $.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.tooltip' );
-    }
-  }; // Plugin end
-}( jQuery ));
-;(function ($) {
-  $(document).ready(function() {
-
-    $(document).on('click.card', '.card', function (e) {
-      if ($(this).find('> .card-reveal').length) {
-        if ($(e.target).is($('.card-reveal .card-title')) || $(e.target).is($('.card-reveal .card-title i'))) {
-          // Make Reveal animate down and display none
-          $(this).find('.card-reveal').velocity(
-            {translateY: 0}, {
-              duration: 225,
-              queue: false,
-              easing: 'easeInOutQuad',
-              complete: function() { $(this).css({ display: 'none'}); }
-            }
-          );
-        }
-        else if ($(e.target).is($('.card .activator')) ||
-                 $(e.target).is($('.card .activator i')) ) {
-          $(e.target).closest('.card').css('overflow', 'hidden');
-          $(this).find('.card-reveal').css({ display: 'block'}).velocity("stop", false).velocity({translateY: '-100%'}, {duration: 300, queue: false, easing: 'easeInOutQuad'});
-        }
-      }
-    });
-
-  });
-}( jQuery ));;(function ($) {
-  var materialChipsDefaults = {
-    data: [],
-    placeholder: '',
-    secondaryPlaceholder: '',
-    autocompleteData: {},
-    autocompleteLimit: Infinity,
-  };
-
-  $(document).ready(function() {
-    // Handle removal of static chips.
-    $(document).on('click', '.chip .close', function(e){
-      var $chips = $(this).closest('.chips');
-      if ($chips.attr('data-initialized')) {
-        return;
-      }
-      $(this).closest('.chip').remove();
-    });
-  });
-
-  $.fn.material_chip = function (options) {
-    var self = this;
-    this.$el = $(this);
-    this.$document = $(document);
-    this.SELS = {
-      CHIPS: '.chips',
-      CHIP: '.chip',
-      INPUT: 'input',
-      DELETE: '.material-icons',
-      SELECTED_CHIP: '.selected',
-    };
-
-    if ('data' === options) {
-      return this.$el.data('chips');
-    }
-
-    var curr_options = $.extend({}, materialChipsDefaults, options);
-    self.hasAutocomplete = !$.isEmptyObject(curr_options.autocompleteData);
-
-    // Initialize
-    this.init = function() {
-      var i = 0;
-      var chips;
-      self.$el.each(function(){
-        var $chips = $(this);
-        var chipId = Materialize.guid();
-        self.chipId = chipId;
-
-        if (!curr_options.data || !(curr_options.data instanceof Array)) {
-          curr_options.data = [];
-        }
-        $chips.data('chips', curr_options.data);
-        $chips.attr('data-index', i);
-        $chips.attr('data-initialized', true);
-
-        if (!$chips.hasClass(self.SELS.CHIPS)) {
-          $chips.addClass('chips');
-        }
-
-        self.chips($chips, chipId);
-        i++;
-      });
-    };
-
-    this.handleEvents = function() {
-      var SELS = self.SELS;
-
-      self.$document.off('click.chips-focus', SELS.CHIPS).on('click.chips-focus', SELS.CHIPS, function(e){
-        $(e.target).find(SELS.INPUT).focus();
-      });
-
-      self.$document.off('click.chips-select', SELS.CHIP).on('click.chips-select', SELS.CHIP, function(e){
-        var $chip = $(e.target);
-        if ($chip.length) {
-          var wasSelected = $chip.hasClass('selected');
-          var $chips = $chip.closest(SELS.CHIPS);
-          $(SELS.CHIP).removeClass('selected');
-
-          if (!wasSelected) {
-            self.selectChip($chip.index(), $chips);
-          }
-        }
-      });
-
-      self.$document.off('keydown.chips').on('keydown.chips', function(e){
-        if ($(e.target).is('input, textarea')) {
-          return;
-        }
-
-        // delete
-        var $chip = self.$document.find(SELS.CHIP + SELS.SELECTED_CHIP);
-        var $chips = $chip.closest(SELS.CHIPS);
-        var length = $chip.siblings(SELS.CHIP).length;
-        var index;
-
-        if (!$chip.length) {
-          return;
-        }
-
-        if (e.which === 8 || e.which === 46) {
-          e.preventDefault();
-
-          index = $chip.index();
-          self.deleteChip(index, $chips);
-
-          var selectIndex = null;
-          if ((index + 1) < length) {
-            selectIndex = index;
-          } else if (index === length || (index + 1) === length) {
-            selectIndex = length - 1;
-          }
-
-          if (selectIndex < 0) selectIndex = null;
-
-          if (null !== selectIndex) {
-            self.selectChip(selectIndex, $chips);
-          }
-          if (!length) $chips.find('input').focus();
-
-        // left
-        } else if (e.which === 37) {
-          index = $chip.index() - 1;
-          if (index < 0) {
-            return;
-          }
-          $(SELS.CHIP).removeClass('selected');
-          self.selectChip(index, $chips);
-
-        // right
-        } else if (e.which === 39) {
-          index = $chip.index() + 1;
-          $(SELS.CHIP).removeClass('selected');
-          if (index > length) {
-            $chips.find('input').focus();
-            return;
-          }
-          self.selectChip(index, $chips);
-        }
-      });
-
-      self.$document.off('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){
-        var $currChips = $(e.target).closest(SELS.CHIPS);
-        $currChips.addClass('focus');
-        $currChips.siblings('label, .prefix').addClass('active');
-        $(SELS.CHIP).removeClass('selected');
-      });
-
-      self.$document.off('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){
-        var $currChips = $(e.target).closest(SELS.CHIPS);
-        $currChips.removeClass('focus');
-
-        // Remove active if empty
-        if (!$currChips.data('chips').length) {
-          $currChips.siblings('label').removeClass('active');
-        }
-        $currChips.siblings('.prefix').removeClass('active');
-      });
-
-      self.$document.off('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT).on('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT, function(e){
-        var $target = $(e.target);
-        var $chips = $target.closest(SELS.CHIPS);
-        var chipsLength = $chips.children(SELS.CHIP).length;
-
-        // enter
-        if (13 === e.which) {
-          // Override enter if autocompleting.
-          if (self.hasAutocomplete &&
-              $chips.find('.autocomplete-content.dropdown-content').length &&
-              $chips.find('.autocomplete-content.dropdown-content').children().length) {
-            return;
-          }
-
-          e.preventDefault();
-          self.addChip({tag: $target.val()}, $chips);
-          $target.val('');
-          return;
-        }
-
-        // delete or left
-        if ((8 === e.keyCode || 37 === e.keyCode) && '' === $target.val() && chipsLength) {
-          e.preventDefault();
-          self.selectChip(chipsLength - 1, $chips);
-          $target.blur();
-          return;
-        }
-      });
-
-      // Click on delete icon in chip.
-      self.$document.off('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE).on('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE, function(e) {
-        var $target = $(e.target);
-        var $chips = $target.closest(SELS.CHIPS);
-        var $chip = $target.closest(SELS.CHIP);
-        e.stopPropagation();
-        self.deleteChip($chip.index(), $chips);
-        $chips.find('input').focus();
-      });
-    };
-
-    this.chips = function($chips, chipId) {
-      var html = '';
-      $chips.data('chips').forEach(function(elem){
-        html += self.renderChip(elem);
-      });
-      html += '<input id="' + chipId +'" class="input" placeholder="">';
-      $chips.html(html);
-      self.setPlaceholder($chips);
-
-      // Set for attribute for label
-      var label = $chips.next('label');
-      if (label.length) {
-        label.attr('for', chipId);
-
-        if ($chips.data('chips').length) {
-          label.addClass('active');
-        }
-      }
-
-      // Setup autocomplete if needed.
-      var input = $('#' + chipId);
-      if (self.hasAutocomplete) {
-        input.autocomplete({
-          data: curr_options.autocompleteData,
-          limit: curr_options.autocompleteLimit,
-          onAutocomplete: function(val) {
-            self.addChip({tag: val}, $chips);
-            input.val('');
-            input.focus();
-          },
-        })
-      }
-    };
-
-    this.renderChip = function(elem) {
-      if (!elem.tag) return;
-
-      var html = '<div class="chip">' + elem.tag;
-      if (elem.image) {
-        html += ' <img src="' + elem.image + '"> ';
-      }
-      html += '<i class="material-icons close">close</i>';
-      html += '</div>';
-      return html;
-    };
-
-    this.setPlaceholder = function($chips) {
-      if ($chips.data('chips').length && curr_options.placeholder) {
-        $chips.find('input').prop('placeholder', curr_options.placeholder);
-
-      } else if (!$chips.data('chips').length && curr_options.secondaryPlaceholder) {
-        $chips.find('input').prop('placeholder', curr_options.secondaryPlaceholder);
-      }
-    };
-
-    this.isValid = function($chips, elem) {
-      var chips = $chips.data('chips');
-      var exists = false;
-      for (var i=0; i < chips.length; i++) {
-        if (chips[i].tag === elem.tag) {
-            exists = true;
-            return;
-        }
-      }
-      return '' !== elem.tag && !exists;
-    };
-
-    this.addChip = function(elem, $chips) {
-      if (!self.isValid($chips, elem)) {
-        return;
-      }
-      var chipHtml = self.renderChip(elem);
-      var newData = [];
-      var oldData = $chips.data('chips');
-      for (var i = 0; i < oldData.length; i++) {
-        newData.push(oldData[i]);
-      }
-      newData.push(elem);
-
-      $chips.data('chips', newData);
-      $(chipHtml).insertBefore($chips.find('input'));
-      $chips.trigger('chip.add', elem);
-      self.setPlaceholder($chips);
-    };
-
-    this.deleteChip = function(chipIndex, $chips) {
-      var chip = $chips.data('chips')[chipIndex];
-      $chips.find('.chip').eq(chipIndex).remove();
-
-      var newData = [];
-      var oldData = $chips.data('chips');
-      for (var i = 0; i < oldData.length; i++) {
-        if (i !== chipIndex) {
-          newData.push(oldData[i]);
-        }
-      }
-
-      $chips.data('chips', newData);
-      $chips.trigger('chip.delete', chip);
-      self.setPlaceholder($chips);
-    };
-
-    this.selectChip = function(chipIndex, $chips) {
-      var $chip = $chips.find('.chip').eq(chipIndex);
-      if ($chip && false === $chip.hasClass('selected')) {
-        $chip.addClass('selected');
-        $chips.trigger('chip.select', $chips.data('chips')[chipIndex]);
-      }
-    };
-
-    this.getChipsElement = function(index, $chips) {
-      return $chips.eq(index);
-    };
-
-    // init
-    this.init();
-
-    this.handleEvents();
-  };
-}( jQuery ));
-;(function ($) {
-  $.fn.pushpin = function (options) {
-    // Defaults
-    var defaults = {
-      top: 0,
-      bottom: Infinity,
-      offset: 0
-    };
-
-    // Remove pushpin event and classes
-    if (options === "remove") {
-      this.each(function () {
-        if (id = $(this).data('pushpin-id')) {
-          $(window).off('scroll.' + id);
-          $(this).removeData('pushpin-id').removeClass('pin-top pinned pin-bottom').removeAttr('style');
-        }
-      });
-      return false;
-    }
-
-    options = $.extend(defaults, options);
-
-
-    $index = 0;
-    return this.each(function() {
-      var $uniqueId = Materialize.guid(),
-          $this = $(this),
-          $original_offset = $(this).offset().top;
-
-      function removePinClasses(object) {
-        object.removeClass('pin-top');
-        object.removeClass('pinned');
-        object.removeClass('pin-bottom');
-      }
-
-      function updateElements(objects, scrolled) {
-        objects.each(function () {
-          // Add position fixed (because its between top and bottom)
-          if (options.top <= scrolled && options.bottom >= scrolled && !$(this).hasClass('pinned')) {
-            removePinClasses($(this));
-            $(this).css('top', options.offset);
-            $(this).addClass('pinned');
-          }
-
-          // Add pin-top (when scrolled position is above top)
-          if (scrolled < options.top && !$(this).hasClass('pin-top')) {
-            removePinClasses($(this));
-            $(this).css('top', 0);
-            $(this).addClass('pin-top');
-          }
-
-          // Add pin-bottom (when scrolled position is below bottom)
-          if (scrolled > options.bottom && !$(this).hasClass('pin-bottom')) {
-            removePinClasses($(this));
-            $(this).addClass('pin-bottom');
-            $(this).css('top', options.bottom - $original_offset);
-          }
-        });
-      }
-
-      $(this).data('pushpin-id', $uniqueId);
-      updateElements($this, $(window).scrollTop());
-      $(window).on('scroll.' + $uniqueId, function () {
-        var $scrolled = $(window).scrollTop() + options.offset;
-        updateElements($this, $scrolled);
-      });
-
-    });
-
-  };
-}( jQuery ));;(function ($) {
-  $(document).ready(function() {
-
-    // jQuery reverse
-    $.fn.reverse = [].reverse;
-
-    // Hover behaviour: make sure this doesn't work on .click-to-toggle FABs!
-    $(document).on('mouseenter.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) {
-      var $this = $(this);
-      openFABMenu($this);
-    });
-    $(document).on('mouseleave.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) {
-      var $this = $(this);
-      closeFABMenu($this);
-    });
-
-    // Toggle-on-click behaviour.
-    $(document).on('click.fabClickToggle', '.fixed-action-btn.click-to-toggle > a', function(e) {
-      var $this = $(this);
-      var $menu = $this.parent();
-      if ($menu.hasClass('active')) {
-        closeFABMenu($menu);
-      } else {
-        openFABMenu($menu);
-      }
-    });
-
-    // Toolbar transition behaviour.
-    $(document).on('click.fabToolbar', '.fixed-action-btn.toolbar > a', function(e) {
-      var $this = $(this);
-      var $menu = $this.parent();
-      FABtoToolbar($menu);
-    });
-
-  });
-
-  $.fn.extend({
-    openFAB: function() {
-      openFABMenu($(this));
-    },
-    closeFAB: function() {
-      closeFABMenu($(this));
-    },
-    openToolbar: function() {
-      FABtoToolbar($(this));
-    },
-    closeToolbar: function() {
-      toolbarToFAB($(this));
-    }
-  });
-
-
-  var openFABMenu = function (btn) {
-    var $this = btn;
-    if ($this.hasClass('active') === false) {
-
-      // Get direction option
-      var horizontal = $this.hasClass('horizontal');
-      var offsetY, offsetX;
-
-      if (horizontal === true) {
-        offsetX = 40;
-      } else {
-        offsetY = 40;
-      }
-
-      $this.addClass('active');
-      $this.find('ul .btn-floating').velocity(
-        { scaleY: ".4", scaleX: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'},
-        { duration: 0 });
-
-      var time = 0;
-      $this.find('ul .btn-floating').reverse().each( function () {
-        $(this).velocity(
-          { opacity: "1", scaleX: "1", scaleY: "1", translateY: "0", translateX: '0'},
-          { duration: 80, delay: time });
-        time += 40;
-      });
-    }
-  };
-
-  var closeFABMenu = function (btn) {
-    var $this = btn;
-    // Get direction option
-    var horizontal = $this.hasClass('horizontal');
-    var offsetY, offsetX;
-
-    if (horizontal === true) {
-      offsetX = 40;
-    } else {
-      offsetY = 40;
-    }
-
-    $this.removeClass('active');
-    var time = 0;
-    $this.find('ul .btn-floating').velocity("stop", true);
-    $this.find('ul .btn-floating').velocity(
-      { opacity: "0", scaleX: ".4", scaleY: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'},
-      { duration: 80 }
-    );
-  };
-
-
-  /**
-   * Transform FAB into toolbar
-   * @param  {Object}  object jQuery object
-   */
-  var FABtoToolbar = function(btn) {
-    if (btn.attr('data-open') === "true") {
-      return;
-    }
-
-    var offsetX, offsetY, scaleFactor;
-    var windowWidth = window.innerWidth;
-    var windowHeight = window.innerHeight;
-    var btnRect = btn[0].getBoundingClientRect();
-    var anchor = btn.find('> a').first();
-    var menu = btn.find('> ul').first();
-    var backdrop = $('<div class="fab-backdrop"></div>');
-    var fabColor = anchor.css('background-color');
-    anchor.append(backdrop);
-
-    offsetX = btnRect.left - (windowWidth / 2) + (btnRect.width / 2);
-    offsetY = windowHeight - btnRect.bottom;
-    scaleFactor = windowWidth / backdrop.width();
-    btn.attr('data-origin-bottom', btnRect.bottom);
-    btn.attr('data-origin-left', btnRect.left);
-    btn.attr('data-origin-width', btnRect.width);
-
-    // Set initial state
-    btn.addClass('active');
-    btn.attr('data-open', true);
-    btn.css({
-      'text-align': 'center',
-      width: '100%',
-      bottom: 0,
-      left: 0,
-      transform: 'translateX(' + offsetX + 'px)',
-      transition: 'none'
-    });
-    anchor.css({
-      transform: 'translateY(' + -offsetY + 'px)',
-      transition: 'none'
-    });
-    backdrop.css({
-      'background-color': fabColor
-    });
-
-
-    setTimeout(function() {
-      btn.css({
-        transform: '',
-        transition: 'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s'
-      });
-      anchor.css({
-        overflow: 'visible',
-        transform: '',
-        transition: 'transform .2s'
-      });
-
-      setTimeout(function() {
-        btn.css({
-          overflow: 'hidden',
-          'background-color': fabColor
-        });
-        backdrop.css({
-          transform: 'scale(' + scaleFactor + ')',
-          transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'
-        });
-        menu.find('> li > a').css({
-          opacity: 1
-        });
-
-        // Scroll to close.
-        $(window).on('scroll.fabToolbarClose', function() {
-          toolbarToFAB(btn);
-          $(window).off('scroll.fabToolbarClose');
-          $(document).off('click.fabToolbarClose');
-        });
-
-        $(document).on('click.fabToolbarClose', function(e) {
-          if (!$(e.target).closest(menu).length) {
-            toolbarToFAB(btn);
-            $(window).off('scroll.fabToolbarClose');
-            $(document).off('click.fabToolbarClose');
-          }
-        });
-      }, 100);
-    }, 0);
-  };
-
-  /**
-   * Transform toolbar back into FAB
-   * @param  {Object}  object jQuery object
-   */
-  var toolbarToFAB = function(btn) {
-    if (btn.attr('data-open') !== "true") {
-      return;
-    }
-
-    var offsetX, offsetY, scaleFactor;
-    var windowWidth = window.innerWidth;
-    var windowHeight = window.innerHeight;
-    var btnWidth = btn.attr('data-origin-width');
-    var btnBottom = btn.attr('data-origin-bottom');
-    var btnLeft = btn.attr('data-origin-left');
-    var anchor = btn.find('> .btn-floating').first();
-    var menu = btn.find('> ul').first();
-    var backdrop = btn.find('.fab-backdrop');
-    var fabColor = anchor.css('background-color');
-
-    offsetX = btnLeft - (windowWidth / 2) + (btnWidth / 2);
-    offsetY = windowHeight - btnBottom;
-    scaleFactor = windowWidth / backdrop.width();
-
-
-    // Hide backdrop
-    btn.removeClass('active');
-    btn.attr('data-open', false);
-    btn.css({
-      'background-color': 'transparent',
-      transition: 'none'
-    });
-    anchor.css({
-      transition: 'none'
-    });
-    backdrop.css({
-      transform: 'scale(0)',
-      'background-color': fabColor
-    });
-    menu.find('> li > a').css({
-      opacity: ''
-    });
-
-    setTimeout(function() {
-      backdrop.remove();
-
-      // Set initial state.
-      btn.css({
-        'text-align': '',
-        width: '',
-        bottom: '',
-        left: '',
-        overflow: '',
-        'background-color': '',
-        transform: 'translate3d(' + -offsetX + 'px,0,0)'
-      });
-      anchor.css({
-        overflow: '',
-        transform: 'translate3d(0,' + offsetY + 'px,0)'
-      });
-
-      setTimeout(function() {
-        btn.css({
-          transform: 'translate3d(0,0,0)',
-          transition: 'transform .2s'
-        });
-        anchor.css({
-          transform: 'translate3d(0,0,0)',
-          transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'
-        });
-      }, 20);
-    }, 200);
-  };
-
-
-}( jQuery ));
-;(function ($) {
-  // Image transition function
-  Materialize.fadeInImage = function(selectorOrEl) {
-    var element;
-    if (typeof(selectorOrEl) === 'string') {
-      element = $(selectorOrEl);
-    } else if (typeof(selectorOrEl) === 'object') {
-      element = selectorOrEl;
-    } else {
-      return;
-    }
-    element.css({opacity: 0});
-    $(element).velocity({opacity: 1}, {
-      duration: 650,
-      queue: false,
-      easing: 'easeOutSine'
-    });
-    $(element).velocity({opacity: 1}, {
-      duration: 1300,
-      queue: false,
-      easing: 'swing',
-      step: function(now, fx) {
-        fx.start = 100;
-        var grayscale_setting = now/100;
-        var brightness_setting = 150 - (100 - now)/1.75;
-
-        if (brightness_setting < 100) {
-          brightness_setting = 100;
-        }
-        if (now >= 0) {
-          $(this).css({
-              "-webkit-filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)",
-              "filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)"
-          });
-        }
-      }
-    });
-  };
-
-  // Horizontal staggered list
-  Materialize.showStaggeredList = function(selectorOrEl) {
-    var element;
-    if (typeof(selectorOrEl) === 'string') {
-      element = $(selectorOrEl);
-    } else if (typeof(selectorOrEl) === 'object') {
-      element = selectorOrEl;
-    } else {
-      return;
-    }
-    var time = 0;
-    element.find('li').velocity(
-        { translateX: "-100px"},
-        { duration: 0 });
-
-    element.find('li').each(function() {
-      $(this).velocity(
-        { opacity: "1", translateX: "0"},
-        { duration: 800, delay: time, easing: [60, 10] });
-      time += 120;
-    });
-  };
-
-
-  $(document).ready(function() {
-    // Hardcoded .staggered-list scrollFire
-    // var staggeredListOptions = [];
-    // $('ul.staggered-list').each(function (i) {
-
-    //   var label = 'scrollFire-' + i;
-    //   $(this).addClass(label);
-    //   staggeredListOptions.push(
-    //     {selector: 'ul.staggered-list.' + label,
-    //      offset: 200,
-    //      callback: 'showStaggeredList("ul.staggered-list.' + label + '")'});
-    // });
-    // scrollFire(staggeredListOptions);
-
-    // HammerJS, Swipe navigation
-
-    // Touch Event
-    var swipeLeft = false;
-    var swipeRight = false;
-
-
-    // Dismissible Collections
-    $('.dismissable').each(function() {
-      $(this).hammer({
-        prevent_default: false
-      }).bind('pan', function(e) {
-        if (e.gesture.pointerType === "touch") {
-          var $this = $(this);
-          var direction = e.gesture.direction;
-          var x = e.gesture.deltaX;
-          var velocityX = e.gesture.velocityX;
-
-          $this.velocity({ translateX: x
-              }, {duration: 50, queue: false, easing: 'easeOutQuad'});
-
-          // Swipe Left
-          if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.75)) {
-            swipeLeft = true;
-          }
-
-          // Swipe Right
-          if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.75)) {
-            swipeRight = true;
-          }
-        }
-      }).bind('panend', function(e) {
-        // Reset if collection is moved back into original position
-        if (Math.abs(e.gesture.deltaX) < ($(this).innerWidth() / 2)) {
-          swipeRight = false;
-          swipeLeft = false;
-        }
-
-        if (e.gesture.pointerType === "touch") {
-          var $this = $(this);
-          if (swipeLeft || swipeRight) {
-            var fullWidth;
-            if (swipeLeft) { fullWidth = $this.innerWidth(); }
-            else { fullWidth = -1 * $this.innerWidth(); }
-
-            $this.velocity({ translateX: fullWidth,
-              }, {duration: 100, queue: false, easing: 'easeOutQuad', complete:
-              function() {
-                $this.css('border', 'none');
-                $this.velocity({ height: 0, padding: 0,
-                  }, {duration: 200, queue: false, easing: 'easeOutQuad', complete:
-                    function() { $this.remove(); }
-                  });
-              }
-            });
-          }
-          else {
-            $this.velocity({ translateX: 0,
-              }, {duration: 100, queue: false, easing: 'easeOutQuad'});
-          }
-          swipeLeft = false;
-          swipeRight = false;
-        }
-      });
-
-    });
-
-
-    // time = 0
-    // // Vertical Staggered list
-    // $('ul.staggered-list.vertical li').velocity(
-    //     { translateY: "100px"},
-    //     { duration: 0 });
-
-    // $('ul.staggered-list.vertical li').each(function() {
-    //   $(this).velocity(
-    //     { opacity: "1", translateY: "0"},
-    //     { duration: 800, delay: time, easing: [60, 25] });
-    //   time += 120;
-    // });
-
-    // // Fade in and Scale
-    // $('.fade-in.scale').velocity(
-    //     { scaleX: .4, scaleY: .4, translateX: -600},
-    //     { duration: 0});
-    // $('.fade-in').each(function() {
-    //   $(this).velocity(
-    //     { opacity: "1", scaleX: 1, scaleY: 1, translateX: 0},
-    //     { duration: 800, easing: [60, 10] });
-    // });
-  });
-}( jQuery ));
-;(function($) {
-
-  var scrollFireEventsHandled = false;
-
-  // Input: Array of JSON objects {selector, offset, callback}
-  Materialize.scrollFire = function(options) {
-    var onScroll = function() {
-      var windowScroll = window.pageYOffset + window.innerHeight;
-
-      for (var i = 0 ; i < options.length; i++) {
-        // Get options from each line
-        var value = options[i];
-        var selector = value.selector,
-            offset = value.offset,
-            callback = value.callback;
-
-        var currentElement = document.querySelector(selector);
-        if ( currentElement !== null) {
-          var elementOffset = currentElement.getBoundingClientRect().top + window.pageYOffset;
-
-          if (windowScroll > (elementOffset + offset)) {
-            if (value.done !== true) {
-              if (typeof(callback) === 'function') {
-                callback.call(this, currentElement);
-              } else if (typeof(callback) === 'string') {
-                var callbackFunc = new Function(callback);
-                callbackFunc(currentElement);
-              }
-              value.done = true;
-            }
-          }
-        }
-      }
-    };
-
-
-    var throttledScroll = Materialize.throttle(function() {
-      onScroll();
-    }, options.throttle || 100);
-
-    if (!scrollFireEventsHandled) {
-      window.addEventListener("scroll", throttledScroll);
-      window.addEventListener("resize", throttledScroll);
-      scrollFireEventsHandled = true;
-    }
-
-    // perform a scan once, after current execution context, and after dom is ready
-    setTimeout(throttledScroll, 0);
-  };
-
-})(jQuery);
-;/*!
- * pickadate.js v3.5.0, 2014/04/13
- * By Amsul, http://amsul.ca
- * Hosted on http://amsul.github.io/pickadate.js
- * Licensed under MIT
- */
-
-(function ( factory ) {
-
-    // AMD.
-    if ( typeof define == 'function' && define.amd )
-        define( 'picker', ['jquery'], factory )
-
-    // Node.js/browserify.
-    else if ( typeof exports == 'object' )
-        module.exports = factory( require('jquery') )
-
-    // Browser globals.
-    else this.Picker = factory( jQuery )
-
-}(function( $ ) {
-
-var $window = $( window )
-var $document = $( document )
-var $html = $( document.documentElement )
-
-
-/**
- * The picker constructor that creates a blank picker.
- */
-function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) {
-
-    // If there’s no element, return the picker constructor.
-    if ( !ELEMENT ) return PickerConstructor
-
-
-    var
-        IS_DEFAULT_THEME = false,
-
-
-        // The state of the picker.
-        STATE = {
-            id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) )
-        },
-
-
-        // Merge the defaults and options passed.
-        SETTINGS = COMPONENT ? $.extend( true, {}, COMPONENT.defaults, OPTIONS ) : OPTIONS || {},
-
-
-        // Merge the default classes with the settings classes.
-        CLASSES = $.extend( {}, PickerConstructor.klasses(), SETTINGS.klass ),
-
-
-        // The element node wrapper into a jQuery object.
-        $ELEMENT = $( ELEMENT ),
-
-
-        // Pseudo picker constructor.
-        PickerInstance = function() {
-            return this.start()
-        },
-
-
-        // The picker prototype.
-        P = PickerInstance.prototype = {
-
-            constructor: PickerInstance,
-
-            $node: $ELEMENT,
-
-
-            /**
-             * Initialize everything
-             */
-            start: function() {
-
-                // If it’s already started, do nothing.
-                if ( STATE && STATE.start ) return P
-
-
-                // Update the picker states.
-                STATE.methods = {}
-                STATE.start = true
-                STATE.open = false
-                STATE.type = ELEMENT.type
-
-
-                // Confirm focus state, convert into text input to remove UA stylings,
-                // and set as readonly to prevent keyboard popup.
-                ELEMENT.autofocus = ELEMENT == getActiveElement()
-                ELEMENT.readOnly = !SETTINGS.editable
-                ELEMENT.id = ELEMENT.id || STATE.id
-                if ( ELEMENT.type != 'text' ) {
-                    ELEMENT.type = 'text'
-                }
-
-
-                // Create a new picker component with the settings.
-                P.component = new COMPONENT(P, SETTINGS)
-
-
-                // Create the picker root with a holder and then prepare it.
-                P.$root = $( PickerConstructor._.node('div', createWrappedComponent(), CLASSES.picker, 'id="' + ELEMENT.id + '_root" tabindex="0"') )
-                prepareElementRoot()
-
-
-                // If there’s a format for the hidden input element, create the element.
-                if ( SETTINGS.formatSubmit ) {
-                    prepareElementHidden()
-                }
-
-
-                // Prepare the input element.
-                prepareElement()
-
-
-                // Insert the root as specified in the settings.
-                if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root )
-                else $ELEMENT.after( P.$root )
-
-
-                // Bind the default component and settings events.
-                P.on({
-                    start: P.component.onStart,
-                    render: P.component.onRender,
-                    stop: P.component.onStop,
-                    open: P.component.onOpen,
-                    close: P.component.onClose,
-                    set: P.component.onSet
-                }).on({
-                    start: SETTINGS.onStart,
-                    render: SETTINGS.onRender,
-                    stop: SETTINGS.onStop,
-                    open: SETTINGS.onOpen,
-                    close: SETTINGS.onClose,
-                    set: SETTINGS.onSet
-                })
-
-
-                // Once we’re all set, check the theme in use.
-                IS_DEFAULT_THEME = isUsingDefaultTheme( P.$root.children()[ 0 ] )
-
-
-                // If the element has autofocus, open the picker.
-                if ( ELEMENT.autofocus ) {
-                    P.open()
-                }
-
-
-                // Trigger queued the “start” and “render” events.
-                return P.trigger( 'start' ).trigger( 'render' )
-            }, //start
-
-
-            /**
-             * Render a new picker
-             */
-            render: function( entireComponent ) {
-
-                // Insert a new component holder in the root or box.
-                if ( entireComponent ) P.$root.html( createWrappedComponent() )
-                else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) )
-
-                // Trigger the queued “render” events.
-                return P.trigger( 'render' )
-            }, //render
-
-
-            /**
-             * Destroy everything
-             */
-            stop: function() {
-
-                // If it’s already stopped, do nothing.
-                if ( !STATE.start ) return P
-
-                // Then close the picker.
-                P.close()
-
-                // Remove the hidden field.
-                if ( P._hidden ) {
-                    P._hidden.parentNode.removeChild( P._hidden )
-                }
-
-                // Remove the root.
-                P.$root.remove()
-
-                // Remove the input class, remove the stored data, and unbind
-                // the events (after a tick for IE - see `P.close`).
-                $ELEMENT.removeClass( CLASSES.input ).removeData( NAME )
-                setTimeout( function() {
-                    $ELEMENT.off( '.' + STATE.id )
-                }, 0)
-
-                // Restore the element state
-                ELEMENT.type = STATE.type
-                ELEMENT.readOnly = false
-
-                // Trigger the queued “stop” events.
-                P.trigger( 'stop' )
-
-                // Reset the picker states.
-                STATE.methods = {}
-                STATE.start = false
-
-                return P
-            }, //stop
-
-
-            /**
-             * Open up the picker
-             */
-            open: function( dontGiveFocus ) {
-
-                // If it’s already open, do nothing.
-                if ( STATE.open ) return P
-
-                // Add the “active” class.
-                $ELEMENT.addClass( CLASSES.active )
-                aria( ELEMENT, 'expanded', true )
-
-                // * A Firefox bug, when `html` has `overflow:hidden`, results in
-                //   killing transitions :(. So add the “opened” state on the next tick.
-                //   Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289
-                setTimeout( function() {
-
-                    // Add the “opened” class to the picker root.
-                    P.$root.addClass( CLASSES.opened )
-                    aria( P.$root[0], 'hidden', false )
-
-                }, 0 )
-
-                // If we have to give focus, bind the element and doc events.
-                if ( dontGiveFocus !== false ) {
-
-                    // Set it as open.
-                    STATE.open = true
-
-                    // Prevent the page from scrolling.
-                    if ( IS_DEFAULT_THEME ) {
-                        $html.
-                            css( 'overflow', 'hidden' ).
-                            css( 'padding-right', '+=' + getScrollbarWidth() )
-                    }
-
-                    // Pass focus to the root element’s jQuery object.
-                    // * Workaround for iOS8 to bring the picker’s root into view.
-                    P.$root.eq(0).focus()
-
-                    // Bind the document events.
-                    $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) {
-
-                        var target = event.target
-
-                        // If the target of the event is not the element, close the picker picker.
-                        // * Don’t worry about clicks or focusins on the root because those don’t bubble up.
-                        //   Also, for Firefox, a click on an `option` element bubbles up directly
-                        //   to the doc. So make sure the target wasn't the doc.
-                        // * In Firefox stopPropagation() doesn’t prevent right-click events from bubbling,
-                        //   which causes the picker to unexpectedly close when right-clicking it. So make
-                        //   sure the event wasn’t a right-click.
-                        if ( target != ELEMENT && target != document && event.which != 3 ) {
-
-                            // If the target was the holder that covers the screen,
-                            // keep the element focused to maintain tabindex.
-                            P.close( target === P.$root.children()[0] )
-                        }
-
-                    }).on( 'keydown.' + STATE.id, function( event ) {
-
-                        var
-                            // Get the keycode.
-                            keycode = event.keyCode,
-
-                            // Translate that to a selection change.
-                            keycodeToMove = P.component.key[ keycode ],
-
-                            // Grab the target.
-                            target = event.target
-
-
-                        // On escape, close the picker and give focus.
-                        if ( keycode == 27 ) {
-                            P.close( true )
-                        }
-
-
-                        // Check if there is a key movement or “enter” keypress on the element.
-                        else if ( target == P.$root[0] && ( keycodeToMove || keycode == 13 ) ) {
-
-                            // Prevent the default action to stop page movement.
-                            event.preventDefault()
-
-                            // Trigger the key movement action.
-                            if ( keycodeToMove ) {
-                                PickerConstructor._.trigger( P.component.key.go, P, [ PickerConstructor._.trigger( keycodeToMove ) ] )
-                            }
-
-                            // On “enter”, if the highlighted item isn’t disabled, set the value and close.
-                            else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) {
-                                P.set( 'select', P.component.item.highlight ).close()
-                            }
-                        }
-
-
-                        // If the target is within the root and “enter” is pressed,
-                        // prevent the default action and trigger a click on the target instead.
-                        else if ( $.contains( P.$root[0], target ) && keycode == 13 ) {
-                            event.preventDefault()
-                            target.click()
-                        }
-                    })
-                }
-
-                // Trigger the queued “open” events.
-                return P.trigger( 'open' )
-            }, //open
-
-
-            /**
-             * Close the picker
-             */
-            close: function( giveFocus ) {
-
-                // If we need to give focus, do it before changing states.
-                if ( giveFocus ) {
-                    // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :|
-                    // The focus is triggered *after* the close has completed - causing it
-                    // to open again. So unbind and rebind the event at the next tick.
-                    P.$root.off( 'focus.toOpen' ).eq(0).focus()
-                    setTimeout( function() {
-                        P.$root.on( 'focus.toOpen', handleFocusToOpenEvent )
-                    }, 0 )
-                }
-
-                // Remove the “active” class.
-                $ELEMENT.removeClass( CLASSES.active )
-                aria( ELEMENT, 'expanded', false )
-
-                // * A Firefox bug, when `html` has `overflow:hidden`, results in
-                //   killing transitions :(. So remove the “opened” state on the next tick.
-                //   Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289
-                setTimeout( function() {
-
-                    // Remove the “opened” and “focused” class from the picker root.
-                    P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused )
-                    aria( P.$root[0], 'hidden', true )
-
-                }, 0 )
-
-                // If it’s already closed, do nothing more.
-                if ( !STATE.open ) return P
-
-                // Set it as closed.
-                STATE.open = false
-
-                // Allow the page to scroll.
-                if ( IS_DEFAULT_THEME ) {
-                    $html.
-                        css( 'overflow', '' ).
-                        css( 'padding-right', '-=' + getScrollbarWidth() )
-                }
-
-                // Unbind the document events.
-                $document.off( '.' + STATE.id )
-
-                // Trigger the queued “close” events.
-                return P.trigger( 'close' )
-            }, //close
-
-
-            /**
-             * Clear the values
-             */
-            clear: function( options ) {
-                return P.set( 'clear', null, options )
-            }, //clear
-
-
-            /**
-             * Set something
-             */
-            set: function( thing, value, options ) {
-
-                var thingItem, thingValue,
-                    thingIsObject = $.isPlainObject( thing ),
-                    thingObject = thingIsObject ? thing : {}
-
-                // Make sure we have usable options.
-                options = thingIsObject && $.isPlainObject( value ) ? value : options || {}
-
-                if ( thing ) {
-
-                    // If the thing isn’t an object, make it one.
-                    if ( !thingIsObject ) {
-                        thingObject[ thing ] = value
-                    }
-
-                    // Go through the things of items to set.
-                    for ( thingItem in thingObject ) {
-
-                        // Grab the value of the thing.
-                        thingValue = thingObject[ thingItem ]
-
-                        // First, if the item exists and there’s a value, set it.
-                        if ( thingItem in P.component.item ) {
-                            if ( thingValue === undefined ) thingValue = null
-                            P.component.set( thingItem, thingValue, options )
-                        }
-
-                        // Then, check to update the element value and broadcast a change.
-                        if ( thingItem == 'select' || thingItem == 'clear' ) {
-                            $ELEMENT.
-                                val( thingItem == 'clear' ? '' : P.get( thingItem, SETTINGS.format ) ).
-                                trigger( 'change' )
-                        }
-                    }
-
-                    // Render a new picker.
-                    P.render()
-                }
-
-                // When the method isn’t muted, trigger queued “set” events and pass the `thingObject`.
-                return options.muted ? P : P.trigger( 'set', thingObject )
-            }, //set
-
-
-            /**
-             * Get something
-             */
-            get: function( thing, format ) {
-
-                // Make sure there’s something to get.
-                thing = thing || 'value'
-
-                // If a picker state exists, return that.
-                if ( STATE[ thing ] != null ) {
-                    return STATE[ thing ]
-                }
-
-                // Return the submission value, if that.
-                if ( thing == 'valueSubmit' ) {
-                    if ( P._hidden ) {
-                        return P._hidden.value
-                    }
-                    thing = 'value'
-                }
-
-                // Return the value, if that.
-                if ( thing == 'value' ) {
-                    return ELEMENT.value
-                }
-
-                // Check if a component item exists, return that.
-                if ( thing in P.component.item ) {
-                    if ( typeof format == 'string' ) {
-                        var thingValue = P.component.get( thing )
-                        return thingValue ?
-                            PickerConstructor._.trigger(
-                                P.component.formats.toString,
-                                P.component,
-                                [ format, thingValue ]
-                            ) : ''
-                    }
-                    return P.component.get( thing )
-                }
-            }, //get
-
-
-
-            /**
-             * Bind events on the things.
-             */
-            on: function( thing, method, internal ) {
-
-                var thingName, thingMethod,
-                    thingIsObject = $.isPlainObject( thing ),
-                    thingObject = thingIsObject ? thing : {}
-
-                if ( thing ) {
-
-                    // If the thing isn’t an object, make it one.
-                    if ( !thingIsObject ) {
-                        thingObject[ thing ] = method
-                    }
-
-                    // Go through the things to bind to.
-                    for ( thingName in thingObject ) {
-
-                        // Grab the method of the thing.
-                        thingMethod = thingObject[ thingName ]
-
-                        // If it was an internal binding, prefix it.
-                        if ( internal ) {
-                            thingName = '_' + thingName
-                        }
-
-                        // Make sure the thing methods collection exists.
-                        STATE.methods[ thingName ] = STATE.methods[ thingName ] || []
-
-                        // Add the method to the relative method collection.
-                        STATE.methods[ thingName ].push( thingMethod )
-                    }
-                }
-
-                return P
-            }, //on
-
-
-
-            /**
-             * Unbind events on the things.
-             */
-            off: function() {
-                var i, thingName,
-                    names = arguments;
-                for ( i = 0, namesCount = names.length; i < namesCount; i += 1 ) {
-                    thingName = names[i]
-                    if ( thingName in STATE.methods ) {
-                        delete STATE.methods[thingName]
-                    }
-                }
-                return P
-            },
-
-
-            /**
-             * Fire off method events.
-             */
-            trigger: function( name, data ) {
-                var _trigger = function( name ) {
-                    var methodList = STATE.methods[ name ]
-                    if ( methodList ) {
-                        methodList.map( function( method ) {
-                            PickerConstructor._.trigger( method, P, [ data ] )
-                        })
-                    }
-                }
-                _trigger( '_' + name )
-                _trigger( name )
-                return P
-            } //trigger
-        } //PickerInstance.prototype
-
-
-    /**
-     * Wrap the picker holder components together.
-     */
-    function createWrappedComponent() {
-
-        // Create a picker wrapper holder
-        return PickerConstructor._.node( 'div',
-
-            // Create a picker wrapper node
-            PickerConstructor._.node( 'div',
-
-                // Create a picker frame
-                PickerConstructor._.node( 'div',
-
-                    // Create a picker box node
-                    PickerConstructor._.node( 'div',
-
-                        // Create the components nodes.
-                        P.component.nodes( STATE.open ),
-
-                        // The picker box class
-                        CLASSES.box
-                    ),
-
-                    // Picker wrap class
-                    CLASSES.wrap
-                ),
-
-                // Picker frame class
-                CLASSES.frame
-            ),
-
-            // Picker holder class
-            CLASSES.holder
-        ) //endreturn
-    } //createWrappedComponent
-
-
-
-    /**
-     * Prepare the input element with all bindings.
-     */
-    function prepareElement() {
-
-        $ELEMENT.
-
-            // Store the picker data by component name.
-            data(NAME, P).
-
-            // Add the “input” class name.
-            addClass(CLASSES.input).
-
-            // Remove the tabindex.
-            attr('tabindex', -1).
-
-            // If there’s a `data-value`, update the value of the element.
-            val( $ELEMENT.data('value') ?
-                P.get('select', SETTINGS.format) :
-                ELEMENT.value
-            )
-
-
-        // Only bind keydown events if the element isn’t editable.
-        if ( !SETTINGS.editable ) {
-
-            $ELEMENT.
-
-                // On focus/click, focus onto the root to open it up.
-                on( 'focus.' + STATE.id + ' click.' + STATE.id, function( event ) {
-                    event.preventDefault()
-                    P.$root.eq(0).focus()
-                }).
-
-                // Handle keyboard event based on the picker being opened or not.
-                on( 'keydown.' + STATE.id, handleKeydownEvent )
-        }
-
-
-        // Update the aria attributes.
-        aria(ELEMENT, {
-            haspopup: true,
-            expanded: false,
-            readonly: false,
-            owns: ELEMENT.id + '_root'
-        })
-    }
-
-
-    /**
-     * Prepare the root picker element with all bindings.
-     */
-    function prepareElementRoot() {
-
-        P.$root.
-
-            on({
-
-                // For iOS8.
-                keydown: handleKeydownEvent,
-
-                // When something within the root is focused, stop from bubbling
-                // to the doc and remove the “focused” state from the root.
-                focusin: function( event ) {
-                    P.$root.removeClass( CLASSES.focused )
-                    event.stopPropagation()
-                },
-
-                // When something within the root holder is clicked, stop it
-                // from bubbling to the doc.
-                'mousedown click': function( event ) {
-
-                    var target = event.target
-
-                    // Make sure the target isn’t the root holder so it can bubble up.
-                    if ( target != P.$root.children()[ 0 ] ) {
-
-                        event.stopPropagation()
-
-                        // * For mousedown events, cancel the default action in order to
-                        //   prevent cases where focus is shifted onto external elements
-                        //   when using things like jQuery mobile or MagnificPopup (ref: #249 & #120).
-                        //   Also, for Firefox, don’t prevent action on the `option` element.
-                        if ( event.type == 'mousedown' && !$( target ).is( 'input, select, textarea, button, option' )) {
-
-                            event.preventDefault()
-
-                            // Re-focus onto the root so that users can click away
-                            // from elements focused within the picker.
-                            P.$root.eq(0).focus()
-                        }
-                    }
-                }
-            }).
-
-            // Add/remove the “target” class on focus and blur.
-            on({
-                focus: function() {
-                    $ELEMENT.addClass( CLASSES.target )
-                },
-                blur: function() {
-                    $ELEMENT.removeClass( CLASSES.target )
-                }
-            }).
-
-            // Open the picker and adjust the root “focused” state
-            on( 'focus.toOpen', handleFocusToOpenEvent ).
-
-            // If there’s a click on an actionable element, carry out the actions.
-            on( 'click', '[data-pick], [data-nav], [data-clear], [data-close]', function() {
-
-                var $target = $( this ),
-                    targetData = $target.data(),
-                    targetDisabled = $target.hasClass( CLASSES.navDisabled ) || $target.hasClass( CLASSES.disabled ),
-
-                    // * For IE, non-focusable elements can be active elements as well
-                    //   (http://stackoverflow.com/a/2684561).
-                    activeElement = getActiveElement()
-                    activeElement = activeElement && ( activeElement.type || activeElement.href )
-
-                // If it’s disabled or nothing inside is actively focused, re-focus the element.
-                if ( targetDisabled || activeElement && !$.contains( P.$root[0], activeElement ) ) {
-                    P.$root.eq(0).focus()
-                }
-
-                // If something is superficially changed, update the `highlight` based on the `nav`.
-                if ( !targetDisabled && targetData.nav ) {
-                    P.set( 'highlight', P.component.item.highlight, { nav: targetData.nav } )
-                }
-
-                // If something is picked, set `select` then close with focus.
-                else if ( !targetDisabled && 'pick' in targetData ) {
-                    P.set( 'select', targetData.pick )
-                }
-
-                // If a “clear” button is pressed, empty the values and close with focus.
-                else if ( targetData.clear ) {
-                    P.clear().close( true )
-                }
-
-                else if ( targetData.close ) {
-                    P.close( true )
-                }
-
-            }) //P.$root
-
-        aria( P.$root[0], 'hidden', true )
-    }
-
-
-     /**
-      * Prepare the hidden input element along with all bindings.
-      */
-    function prepareElementHidden() {
-
-        var name
-
-        if ( SETTINGS.hiddenName === true ) {
-            name = ELEMENT.name
-            ELEMENT.name = ''
-        }
-        else {
-            name = [
-                typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '',
-                typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit'
-            ]
-            name = name[0] + ELEMENT.name + name[1]
-        }
-
-        P._hidden = $(
-            '<input ' +
-            'type=hidden ' +
-
-            // Create the name using the original input’s with a prefix and suffix.
-            'name="' + name + '"' +
-
-            // If the element has a value, set the hidden value as well.
-            (
-                $ELEMENT.data('value') || ELEMENT.value ?
-                    ' value="' + P.get('select', SETTINGS.formatSubmit) + '"' :
-                    ''
-            ) +
-            '>'
-        )[0]
-
-        $ELEMENT.
-
-            // If the value changes, update the hidden input with the correct format.
-            on('change.' + STATE.id, function() {
-                P._hidden.value = ELEMENT.value ?
-                    P.get('select', SETTINGS.formatSubmit) :
-                    ''
-            })
-
-
-        // Insert the hidden input as specified in the settings.
-        if ( SETTINGS.container ) $( SETTINGS.container ).append( P._hidden )
-        else $ELEMENT.after( P._hidden )
-    }
-
-
-    // For iOS8.
-    function handleKeydownEvent( event ) {
-
-        var keycode = event.keyCode,
-
-            // Check if one of the delete keys was pressed.
-            isKeycodeDelete = /^(8|46)$/.test(keycode)
-
-        // For some reason IE clears the input value on “escape”.
-        if ( keycode == 27 ) {
-            P.close()
-            return false
-        }
-
-        // Check if `space` or `delete` was pressed or the picker is closed with a key movement.
-        if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) {
-
-            // Prevent it from moving the page and bubbling to doc.
-            event.preventDefault()
-            event.stopPropagation()
-
-            // If `delete` was pressed, clear the values and close the picker.
-            // Otherwise open the picker.
-            if ( isKeycodeDelete ) { P.clear().close() }
-            else { P.open() }
-        }
-    }
-
-
-    // Separated for IE
-    function handleFocusToOpenEvent( event ) {
-
-        // Stop the event from propagating to the doc.
-        event.stopPropagation()
-
-        // If it’s a focus event, add the “focused” class to the root.
-        if ( event.type == 'focus' ) {
-            P.$root.addClass( CLASSES.focused )
-        }
-
-        // And then finally open the picker.
-        P.open()
-    }
-
-
-    // Return a new picker instance.
-    return new PickerInstance()
-} //PickerConstructor
-
-
-
-/**
- * The default classes and prefix to use for the HTML classes.
- */
-PickerConstructor.klasses = function( prefix ) {
-    prefix = prefix || 'picker'
-    return {
-
-        picker: prefix,
-        opened: prefix + '--opened',
-        focused: prefix + '--focused',
-
-        input: prefix + '__input',
-        active: prefix + '__input--active',
-        target: prefix + '__input--target',
-
-        holder: prefix + '__holder',
-
-        frame: prefix + '__frame',
-        wrap: prefix + '__wrap',
-
-        box: prefix + '__box'
-    }
-} //PickerConstructor.klasses
-
-
-
-/**
- * Check if the default theme is being used.
- */
-function isUsingDefaultTheme( element ) {
-
-    var theme,
-        prop = 'position'
-
-    // For IE.
-    if ( element.currentStyle ) {
-        theme = element.currentStyle[prop]
-    }
-
-    // For normal browsers.
-    else if ( window.getComputedStyle ) {
-        theme = getComputedStyle( element )[prop]
-    }
-
-    return theme == 'fixed'
-}
-
-
-
-/**
- * Get the width of the browser’s scrollbar.
- * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js
- */
-function getScrollbarWidth() {
-
-    if ( $html.height() <= $window.height() ) {
-        return 0
-    }
-
-    var $outer = $( '<div style="visibility:hidden;width:100px" />' ).
-        appendTo( 'body' )
-
-    // Get the width without scrollbars.
-    var widthWithoutScroll = $outer[0].offsetWidth
-
-    // Force adding scrollbars.
-    $outer.css( 'overflow', 'scroll' )
-
-    // Add the inner div.
-    var $inner = $( '<div style="width:100%" />' ).appendTo( $outer )
-
-    // Get the width with scrollbars.
-    var widthWithScroll = $inner[0].offsetWidth
-
-    // Remove the divs.
-    $outer.remove()
-
-    // Return the difference between the widths.
-    return widthWithoutScroll - widthWithScroll
-}
-
-
-
-/**
- * PickerConstructor helper methods.
- */
-PickerConstructor._ = {
-
-    /**
-     * Create a group of nodes. Expects:
-     * `
-        {
-            min:    {Integer},
-            max:    {Integer},
-            i:      {Integer},
-            node:   {String},
-            item:   {Function}
-        }
-     * `
-     */
-    group: function( groupObject ) {
-
-        var
-            // Scope for the looped object
-            loopObjectScope,
-
-            // Create the nodes list
-            nodesList = '',
-
-            // The counter starts from the `min`
-            counter = PickerConstructor._.trigger( groupObject.min, groupObject )
-
-
-        // Loop from the `min` to `max`, incrementing by `i`
-        for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) {
-
-            // Trigger the `item` function within scope of the object
-            loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] )
-
-            // Splice the subgroup and create nodes out of the sub nodes
-            nodesList += PickerConstructor._.node(
-                groupObject.node,
-                loopObjectScope[ 0 ],   // the node
-                loopObjectScope[ 1 ],   // the classes
-                loopObjectScope[ 2 ]    // the attributes
-            )
-        }
-
-        // Return the list of nodes
-        return nodesList
-    }, //group
-
-
-    /**
-     * Create a dom node string
-     */
-    node: function( wrapper, item, klass, attribute ) {
-
-        // If the item is false-y, just return an empty string
-        if ( !item ) return ''
-
-        // If the item is an array, do a join
-        item = $.isArray( item ) ? item.join( '' ) : item
-
-        // Check for the class
-        klass = klass ? ' class="' + klass + '"' : ''
-
-        // Check for any attributes
-        attribute = attribute ? ' ' + attribute : ''
-
-        // Return the wrapped item
-        return '<' + wrapper + klass + attribute + '>' + item + '</' + wrapper + '>'
-    }, //node
-
-
-    /**
-     * Lead numbers below 10 with a zero.
-     */
-    lead: function( number ) {
-        return ( number < 10 ? '0': '' ) + number
-    },
-
-
-    /**
-     * Trigger a function otherwise return the value.
-     */
-    trigger: function( callback, scope, args ) {
-        return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback
-    },
-
-
-    /**
-     * If the second character is a digit, length is 2 otherwise 1.
-     */
-    digits: function( string ) {
-        return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1
-    },
-
-
-    /**
-     * Tell if something is a date object.
-     */
-    isDate: function( value ) {
-        return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() )
-    },
-
-
-    /**
-     * Tell if something is an integer.
-     */
-    isInteger: function( value ) {
-        return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0
-    },
-
-
-    /**
-     * Create ARIA attribute strings.
-     */
-    ariaAttr: ariaAttr
-} //PickerConstructor._
-
-
-
-/**
- * Extend the picker with a component and defaults.
- */
-PickerConstructor.extend = function( name, Component ) {
-
-    // Extend jQuery.
-    $.fn[ name ] = function( options, action ) {
-
-        // Grab the component data.
-        var componentData = this.data( name )
-
-        // If the picker is requested, return the data object.
-        if ( options == 'picker' ) {
-            return componentData
-        }
-
-        // If the component data exists and `options` is a string, carry out the action.
-        if ( componentData && typeof options == 'string' ) {
-            return PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] )
-        }
-
-        // Otherwise go through each matched element and if the component
-        // doesn’t exist, create a new picker using `this` element
-        // and merging the defaults and options with a deep copy.
-        return this.each( function() {
-            var $this = $( this )
-            if ( !$this.data( name ) ) {
-                new PickerConstructor( this, name, Component, options )
-            }
-        })
-    }
-
-    // Set the defaults.
-    $.fn[ name ].defaults = Component.defaults
-} //PickerConstructor.extend
-
-
-
-function aria(element, attribute, value) {
-    if ( $.isPlainObject(attribute) ) {
-        for ( var key in attribute ) {
-            ariaSet(element, key, attribute[key])
-        }
-    }
-    else {
-        ariaSet(element, attribute, value)
-    }
-}
-function ariaSet(element, attribute, value) {
-    element.setAttribute(
-        (attribute == 'role' ? '' : 'aria-') + attribute,
-        value
-    )
-}
-function ariaAttr(attribute, data) {
-    if ( !$.isPlainObject(attribute) ) {
-        attribute = { attribute: data }
-    }
-    data = ''
-    for ( var key in attribute ) {
-        var attr = (key == 'role' ? '' : 'aria-') + key,
-            attrVal = attribute[key]
-        data += attrVal == null ? '' : attr + '="' + attribute[key] + '"'
-    }
-    return data
-}
-
-// IE8 bug throws an error for activeElements within iframes.
-function getActiveElement() {
-    try {
-        return document.activeElement
-    } catch ( err ) { }
-}
-
-
-
-// Expose the picker constructor.
-return PickerConstructor
-
-
-}));
-
-
-;/*!
- * Date picker for pickadate.js v3.5.0
- * http://amsul.github.io/pickadate.js/date.htm
- */
-
-(function ( factory ) {
-
-    // AMD.
-    if ( typeof define == 'function' && define.amd )
-        define( ['picker', 'jquery'], factory )
-
-    // Node.js/browserify.
-    else if ( typeof exports == 'object' )
-        module.exports = factory( require('./picker.js'), require('jquery') )
-
-    // Browser globals.
-    else factory( Picker, jQuery )
-
-}(function( Picker, $ ) {
-
-
-/**
- * Globals and constants
- */
-var DAYS_IN_WEEK = 7,
-    WEEKS_IN_CALENDAR = 6,
-    _ = Picker._
-
-
-
-/**
- * The date picker constructor
- */
-function DatePicker( picker, settings ) {
-
-    var calendar = this,
-        element = picker.$node[ 0 ],
-        elementValue = element.value,
-        elementDataValue = picker.$node.data( 'value' ),
-        valueString = elementDataValue || elementValue,
-        formatString = elementDataValue ? settings.formatSubmit : settings.format,
-        isRTL = function() {
-
-            return element.currentStyle ?
-
-                // For IE.
-                element.currentStyle.direction == 'rtl' :
-
-                // For normal browsers.
-                getComputedStyle( picker.$root[0] ).direction == 'rtl'
-        }
-
-    calendar.settings = settings
-    calendar.$node = picker.$node
-
-    // The queue of methods that will be used to build item objects.
-    calendar.queue = {
-        min: 'measure create',
-        max: 'measure create',
-        now: 'now create',
-        select: 'parse create validate',
-        highlight: 'parse navigate create validate',
-        view: 'parse create validate viewset',
-        disable: 'deactivate',
-        enable: 'activate'
-    }
-
-    // The component's item object.
-    calendar.item = {}
-
-    calendar.item.clear = null
-    calendar.item.disable = ( settings.disable || [] ).slice( 0 )
-    calendar.item.enable = -(function( collectionDisabled ) {
-        return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1
-    })( calendar.item.disable )
-
-    calendar.
-        set( 'min', settings.min ).
-        set( 'max', settings.max ).
-        set( 'now' )
-
-    // When there’s a value, set the `select`, which in turn
-    // also sets the `highlight` and `view`.
-    if ( valueString ) {
-        calendar.set( 'select', valueString, { format: formatString })
-    }
-
-    // If there’s no value, default to highlighting “today”.
-    else {
-        calendar.
-            set( 'select', null ).
-            set( 'highlight', calendar.item.now )
-    }
-
-
-    // The keycode to movement mapping.
-    calendar.key = {
-        40: 7, // Down
-        38: -7, // Up
-        39: function() { return isRTL() ? -1 : 1 }, // Right
-        37: function() { return isRTL() ? 1 : -1 }, // Left
-        go: function( timeChange ) {
-            var highlightedObject = calendar.item.highlight,
-                targetDate = new Date( highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange )
-            calendar.set(
-                'highlight',
-                targetDate,
-                { interval: timeChange }
-            )
-            this.render()
-        }
-    }
-
-
-    // Bind some picker events.
-    picker.
-        on( 'render', function() {
-            picker.$root.find( '.' + settings.klass.selectMonth ).on( 'change', function() {
-                var value = this.value
-                if ( value ) {
-                    picker.set( 'highlight', [ picker.get( 'view' ).year, value, picker.get( 'highlight' ).date ] )
-                    picker.$root.find( '.' + settings.klass.selectMonth ).trigger( 'focus' )
-                }
-            })
-            picker.$root.find( '.' + settings.klass.selectYear ).on( 'change', function() {
-                var value = this.value
-                if ( value ) {
-                    picker.set( 'highlight', [ value, picker.get( 'view' ).month, picker.get( 'highlight' ).date ] )
-                    picker.$root.find( '.' + settings.klass.selectYear ).trigger( 'focus' )
-                }
-            })
-        }, 1 ).
-        on( 'open', function() {
-            var includeToday = ''
-            if ( calendar.disabled( calendar.get('now') ) ) {
-                includeToday = ':not(.' + settings.klass.buttonToday + ')'
-            }
-            picker.$root.find( 'button' + includeToday + ', select' ).attr( 'disabled', false )
-        }, 1 ).
-        on( 'close', function() {
-            picker.$root.find( 'button, select' ).attr( 'disabled', true )
-        }, 1 )
-
-} //DatePicker
-
-
-/**
- * Set a datepicker item object.
- */
-DatePicker.prototype.set = function( type, value, options ) {
-
-    var calendar = this,
-        calendarItem = calendar.item
-
-    // If the value is `null` just set it immediately.
-    if ( value === null ) {
-        if ( type == 'clear' ) type = 'select'
-        calendarItem[ type ] = value
-        return calendar
-    }
-
-    // Otherwise go through the queue of methods, and invoke the functions.
-    // Update this as the time unit, and set the final value as this item.
-    // * In the case of `enable`, keep the queue but set `disable` instead.
-    //   And in the case of `flip`, keep the queue but set `enable` instead.
-    calendarItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = calendar.queue[ type ].split( ' ' ).map( function( method ) {
-        value = calendar[ method ]( type, value, options )
-        return value
-    }).pop()
-
-    // Check if we need to cascade through more updates.
-    if ( type == 'select' ) {
-        calendar.set( 'highlight', calendarItem.select, options )
-    }
-    else if ( type == 'highlight' ) {
-        calendar.set( 'view', calendarItem.highlight, options )
-    }
-    else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) {
-        if ( calendarItem.select && calendar.disabled( calendarItem.select ) ) {
-            calendar.set( 'select', calendarItem.select, options )
-        }
-        if ( calendarItem.highlight && calendar.disabled( calendarItem.highlight ) ) {
-            calendar.set( 'highlight', calendarItem.highlight, options )
-        }
-    }
-
-    return calendar
-} //DatePicker.prototype.set
-
-
-/**
- * Get a datepicker item object.
- */
-DatePicker.prototype.get = function( type ) {
-    return this.item[ type ]
-} //DatePicker.prototype.get
-
-
-/**
- * Create a picker date object.
- */
-DatePicker.prototype.create = function( type, value, options ) {
-
-    var isInfiniteValue,
-        calendar = this
-
-    // If there’s no value, use the type as the value.
-    value = value === undefined ? type : value
-
-
-    // If it’s infinity, update the value.
-    if ( value == -Infinity || value == Infinity ) {
-        isInfiniteValue = value
-    }
-
-    // If it’s an object, use the native date object.
-    else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) {
-        value = value.obj
-    }
-
-    // If it’s an array, convert it into a date and make sure
-    // that it’s a valid date – otherwise default to today.
-    else if ( $.isArray( value ) ) {
-        value = new Date( value[ 0 ], value[ 1 ], value[ 2 ] )
-        value = _.isDate( value ) ? value : calendar.create().obj
-    }
-
-    // If it’s a number or date object, make a normalized date.
-    else if ( _.isInteger( value ) || _.isDate( value ) ) {
-        value = calendar.normalize( new Date( value ), options )
-    }
-
-    // If it’s a literal true or any other case, set it to now.
-    else /*if ( value === true )*/ {
-        value = calendar.now( type, value, options )
-    }
-
-    // Return the compiled object.
-    return {
-        year: isInfiniteValue || value.getFullYear(),
-        month: isInfiniteValue || value.getMonth(),
-        date: isInfiniteValue || value.getDate(),
-        day: isInfiniteValue || value.getDay(),
-        obj: isInfiniteValue || value,
-        pick: isInfiniteValue || value.getTime()
-    }
-} //DatePicker.prototype.create
-
-
-/**
- * Create a range limit object using an array, date object,
- * literal “true”, or integer relative to another time.
- */
-DatePicker.prototype.createRange = function( from, to ) {
-
-    var calendar = this,
-        createDate = function( date ) {
-            if ( date === true || $.isArray( date ) || _.isDate( date ) ) {
-                return calendar.create( date )
-            }
-            return date
-        }
-
-    // Create objects if possible.
-    if ( !_.isInteger( from ) ) {
-        from = createDate( from )
-    }
-    if ( !_.isInteger( to ) ) {
-        to = createDate( to )
-    }
-
-    // Create relative dates.
-    if ( _.isInteger( from ) && $.isPlainObject( to ) ) {
-        from = [ to.year, to.month, to.date + from ];
-    }
-    else if ( _.isInteger( to ) && $.isPlainObject( from ) ) {
-        to = [ from.year, from.month, from.date + to ];
-    }
-
-    return {
-        from: createDate( from ),
-        to: createDate( to )
-    }
-} //DatePicker.prototype.createRange
-
-
-/**
- * Check if a date unit falls within a date range object.
- */
-DatePicker.prototype.withinRange = function( range, dateUnit ) {
-    range = this.createRange(range.from, range.to)
-    return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick
-}
-
-
-/**
- * Check if two date range objects overlap.
- */
-DatePicker.prototype.overlapRanges = function( one, two ) {
-
-    var calendar = this
-
-    // Convert the ranges into comparable dates.
-    one = calendar.createRange( one.from, one.to )
-    two = calendar.createRange( two.from, two.to )
-
-    return calendar.withinRange( one, two.from ) || calendar.withinRange( one, two.to ) ||
-        calendar.withinRange( two, one.from ) || calendar.withinRange( two, one.to )
-}
-
-
-/**
- * Get the date today.
- */
-DatePicker.prototype.now = function( type, value, options ) {
-    value = new Date()
-    if ( options && options.rel ) {
-        value.setDate( value.getDate() + options.rel )
-    }
-    return this.normalize( value, options )
-}
-
-
-/**
- * Navigate to next/prev month.
- */
-DatePicker.prototype.navigate = function( type, value, options ) {
-
-    var targetDateObject,
-        targetYear,
-        targetMonth,
-        targetDate,
-        isTargetArray = $.isArray( value ),
-        isTargetObject = $.isPlainObject( value ),
-        viewsetObject = this.item.view/*,
-        safety = 100*/
-
-
-    if ( isTargetArray || isTargetObject ) {
-
-        if ( isTargetObject ) {
-            targetYear = value.year
-            targetMonth = value.month
-            targetDate = value.date
-        }
-        else {
-            targetYear = +value[0]
-            targetMonth = +value[1]
-            targetDate = +value[2]
-        }
-
-        // If we’re navigating months but the view is in a different
-        // month, navigate to the view’s year and month.
-        if ( options && options.nav && viewsetObject && viewsetObject.month !== targetMonth ) {
-            targetYear = viewsetObject.year
-            targetMonth = viewsetObject.month
-        }
-
-        // Figure out the expected target year and month.
-        targetDateObject = new Date( targetYear, targetMonth + ( options && options.nav ? options.nav : 0 ), 1 )
-        targetYear = targetDateObject.getFullYear()
-        targetMonth = targetDateObject.getMonth()
-
-        // If the month we’re going to doesn’t have enough days,
-        // keep decreasing the date until we reach the month’s last date.
-        while ( /*safety &&*/ new Date( targetYear, targetMonth, targetDate ).getMonth() !== targetMonth ) {
-            targetDate -= 1
-            /*safety -= 1
-            if ( !safety ) {
-                throw 'Fell into an infinite loop while navigating to ' + new Date( targetYear, targetMonth, targetDate ) + '.'
-            }*/
-        }
-
-        value = [ targetYear, targetMonth, targetDate ]
-    }
-
-    return value
-} //DatePicker.prototype.navigate
-
-
-/**
- * Normalize a date by setting the hours to midnight.
- */
-DatePicker.prototype.normalize = function( value/*, options*/ ) {
-    value.setHours( 0, 0, 0, 0 )
-    return value
-}
-
-
-/**
- * Measure the range of dates.
- */
-DatePicker.prototype.measure = function( type, value/*, options*/ ) {
-
-    var calendar = this
-
-    // If it’s anything false-y, remove the limits.
-    if ( !value ) {
-        value = type == 'min' ? -Infinity : Infinity
-    }
-
-    // If it’s a string, parse it.
-    else if ( typeof value == 'string' ) {
-        value = calendar.parse( type, value )
-    }
-
-    // If it's an integer, get a date relative to today.
-    else if ( _.isInteger( value ) ) {
-        value = calendar.now( type, value, { rel: value } )
-    }
-
-    return value
-} ///DatePicker.prototype.measure
-
-
-/**
- * Create a viewset object based on navigation.
- */
-DatePicker.prototype.viewset = function( type, dateObject/*, options*/ ) {
-    return this.create([ dateObject.year, dateObject.month, 1 ])
-}
-
-
-/**
- * Validate a date as enabled and shift if needed.
- */
-DatePicker.prototype.validate = function( type, dateObject, options ) {
-
-    var calendar = this,
-
-        // Keep a reference to the original date.
-        originalDateObject = dateObject,
-
-        // Make sure we have an interval.
-        interval = options && options.interval ? options.interval : 1,
-
-        // Check if the calendar enabled dates are inverted.
-        isFlippedBase = calendar.item.enable === -1,
-
-        // Check if we have any enabled dates after/before now.
-        hasEnabledBeforeTarget, hasEnabledAfterTarget,
-
-        // The min & max limits.
-        minLimitObject = calendar.item.min,
-        maxLimitObject = calendar.item.max,
-
-        // Check if we’ve reached the limit during shifting.
-        reachedMin, reachedMax,
-
-        // Check if the calendar is inverted and at least one weekday is enabled.
-        hasEnabledWeekdays = isFlippedBase && calendar.item.disable.filter( function( value ) {
-
-            // If there’s a date, check where it is relative to the target.
-            if ( $.isArray( value ) ) {
-                var dateTime = calendar.create( value ).pick
-                if ( dateTime < dateObject.pick ) hasEnabledBeforeTarget = true
-                else if ( dateTime > dateObject.pick ) hasEnabledAfterTarget = true
-            }
-
-            // Return only integers for enabled weekdays.
-            return _.isInteger( value )
-        }).length/*,
-
-        safety = 100*/
-
-
-
-    // Cases to validate for:
-    // [1] Not inverted and date disabled.
-    // [2] Inverted and some dates enabled.
-    // [3] Not inverted and out of range.
-    //
-    // Cases to **not** validate for:
-    // • Navigating months.
-    // • Not inverted and date enabled.
-    // • Inverted and all dates disabled.
-    // • ..and anything else.
-    if ( !options || !options.nav ) if (
-        /* 1 */ ( !isFlippedBase && calendar.disabled( dateObject ) ) ||
-        /* 2 */ ( isFlippedBase && calendar.disabled( dateObject ) && ( hasEnabledWeekdays || hasEnabledBeforeTarget || hasEnabledAfterTarget ) ) ||
-        /* 3 */ ( !isFlippedBase && (dateObject.pick <= minLimitObject.pick || dateObject.pick >= maxLimitObject.pick) )
-    ) {
-
-
-        // When inverted, flip the direction if there aren’t any enabled weekdays
-        // and there are no enabled dates in the direction of the interval.
-        if ( isFlippedBase && !hasEnabledWeekdays && ( ( !hasEnabledAfterTarget && interval > 0 ) || ( !hasEnabledBeforeTarget && interval < 0 ) ) ) {
-            interval *= -1
-        }
-
-
-        // Keep looping until we reach an enabled date.
-        while ( /*safety &&*/ calendar.disabled( dateObject ) ) {
-
-            /*safety -= 1
-            if ( !safety ) {
-                throw 'Fell into an infinite loop while validating ' + dateObject.obj + '.'
-            }*/
-
-
-            // If we’ve looped into the next/prev month with a large interval, return to the original date and flatten the interval.
-            if ( Math.abs( interval ) > 1 && ( dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month ) ) {
-                dateObject = originalDateObject
-                interval = interval > 0 ? 1 : -1
-            }
-
-
-            // If we’ve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit.
-            if ( dateObject.pick <= minLimitObject.pick ) {
-                reachedMin = true
-                interval = 1
-                dateObject = calendar.create([
-                    minLimitObject.year,
-                    minLimitObject.month,
-                    minLimitObject.date + (dateObject.pick === minLimitObject.pick ? 0 : -1)
-                ])
-            }
-            else if ( dateObject.pick >= maxLimitObject.pick ) {
-                reachedMax = true
-                interval = -1
-                dateObject = calendar.create([
-                    maxLimitObject.year,
-                    maxLimitObject.month,
-                    maxLimitObject.date + (dateObject.pick === maxLimitObject.pick ? 0 : 1)
-                ])
-            }
-
-
-            // If we’ve reached both limits, just break out of the loop.
-            if ( reachedMin && reachedMax ) {
-                break
-            }
-
-
-            // Finally, create the shifted date using the interval and keep looping.
-            dateObject = calendar.create([ dateObject.year, dateObject.month, dateObject.date + interval ])
-        }
-
-    } //endif
-
-
-    // Return the date object settled on.
-    return dateObject
-} //DatePicker.prototype.validate
-
-
-/**
- * Check if a date is disabled.
- */
-DatePicker.prototype.disabled = function( dateToVerify ) {
-
-    var
-        calendar = this,
-
-        // Filter through the disabled dates to check if this is one.
-        isDisabledMatch = calendar.item.disable.filter( function( dateToDisable ) {
-
-            // If the date is a number, match the weekday with 0index and `firstDay` check.
-            if ( _.isInteger( dateToDisable ) ) {
-                return dateToVerify.day === ( calendar.settings.firstDay ? dateToDisable : dateToDisable - 1 ) % 7
-            }
-
-            // If it’s an array or a native JS date, create and match the exact date.
-            if ( $.isArray( dateToDisable ) || _.isDate( dateToDisable ) ) {
-                return dateToVerify.pick === calendar.create( dateToDisable ).pick
-            }
-
-            // If it’s an object, match a date within the “from” and “to” range.
-            if ( $.isPlainObject( dateToDisable ) ) {
-                return calendar.withinRange( dateToDisable, dateToVerify )
-            }
-        })
-
-    // If this date matches a disabled date, confirm it’s not inverted.
-    isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( dateToDisable ) {
-        return $.isArray( dateToDisable ) && dateToDisable[3] == 'inverted' ||
-            $.isPlainObject( dateToDisable ) && dateToDisable.inverted
-    }).length
-
-    // Check the calendar “enabled” flag and respectively flip the
-    // disabled state. Then also check if it’s beyond the min/max limits.
-    return calendar.item.enable === -1 ? !isDisabledMatch : isDisabledMatch ||
-        dateToVerify.pick < calendar.item.min.pick ||
-        dateToVerify.pick > calendar.item.max.pick
-
-} //DatePicker.prototype.disabled
-
-
-/**
- * Parse a string into a usable type.
- */
-DatePicker.prototype.parse = function( type, value, options ) {
-
-    var calendar = this,
-        parsingObject = {}
-
-    // If it’s already parsed, we’re good.
-    if ( !value || typeof value != 'string' ) {
-        return value
-    }
-
-    // We need a `.format` to parse the value with.
-    if ( !( options && options.format ) ) {
-        options = options || {}
-        options.format = calendar.settings.format
-    }
-
-    // Convert the format into an array and then map through it.
-    calendar.formats.toArray( options.format ).map( function( label ) {
-
-        var
-            // Grab the formatting label.
-            formattingLabel = calendar.formats[ label ],
-
-            // The format length is from the formatting label function or the
-            // label length without the escaping exclamation (!) mark.
-            formatLength = formattingLabel ? _.trigger( formattingLabel, calendar, [ value, parsingObject ] ) : label.replace( /^!/, '' ).length
-
-        // If there's a format label, split the value up to the format length.
-        // Then add it to the parsing object with appropriate label.
-        if ( formattingLabel ) {
-            parsingObject[ label ] = value.substr( 0, formatLength )
-        }
-
-        // Update the value as the substring from format length to end.
-        value = value.substr( formatLength )
-    })
-
-    // Compensate for month 0index.
-    return [
-        parsingObject.yyyy || parsingObject.yy,
-        +( parsingObject.mm || parsingObject.m ) - 1,
-        parsingObject.dd || parsingObject.d
-    ]
-} //DatePicker.prototype.parse
-
-
-/**
- * Various formats to display the object in.
- */
-DatePicker.prototype.formats = (function() {
-
-    // Return the length of the first word in a collection.
-    function getWordLengthFromCollection( string, collection, dateObject ) {
-
-        // Grab the first word from the string.
-        var word = string.match( /\w+/ )[ 0 ]
-
-        // If there's no month index, add it to the date object
-        if ( !dateObject.mm && !dateObject.m ) {
-            dateObject.m = collection.indexOf( word ) + 1
-        }
-
-        // Return the length of the word.
-        return word.length
-    }
-
-    // Get the length of the first word in a string.
-    function getFirstWordLength( string ) {
-        return string.match( /\w+/ )[ 0 ].length
-    }
-
-    return {
-
-        d: function( string, dateObject ) {
-
-            // If there's string, then get the digits length.
-            // Otherwise return the selected date.
-            return string ? _.digits( string ) : dateObject.date
-        },
-        dd: function( string, dateObject ) {
-
-            // If there's a string, then the length is always 2.
-            // Otherwise return the selected date with a leading zero.
-            return string ? 2 : _.lead( dateObject.date )
-        },
-        ddd: function( string, dateObject ) {
-
-            // If there's a string, then get the length of the first word.
-            // Otherwise return the short selected weekday.
-            return string ? getFirstWordLength( string ) : this.settings.weekdaysShort[ dateObject.day ]
-        },
-        dddd: function( string, dateObject ) {
-
-            // If there's a string, then get the length of the first word.
-            // Otherwise return the full selected weekday.
-            return string ? getFirstWordLength( string ) : this.settings.weekdaysFull[ dateObject.day ]
-        },
-        m: function( string, dateObject ) {
-
-            // If there's a string, then get the length of the digits
-            // Otherwise return the selected month with 0index compensation.
-            return string ? _.digits( string ) : dateObject.month + 1
-        },
-        mm: function( string, dateObject ) {
-
-            // If there's a string, then the length is always 2.
-            // Otherwise return the selected month with 0index and leading zero.
-            return string ? 2 : _.lead( dateObject.month + 1 )
-        },
-        mmm: function( string, dateObject ) {
-
-            var collection = this.settings.monthsShort
-
-            // If there's a string, get length of the relevant month from the short
-            // months collection. Otherwise return the selected month from that collection.
-            return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ]
-        },
-        mmmm: function( string, dateObject ) {
-
-            var collection = this.settings.monthsFull
-
-            // If there's a string, get length of the relevant month from the full
-            // months collection. Otherwise return the selected month from that collection.
-            return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ]
-        },
-        yy: function( string, dateObject ) {
-
-            // If there's a string, then the length is always 2.
-            // Otherwise return the selected year by slicing out the first 2 digits.
-            return string ? 2 : ( '' + dateObject.year ).slice( 2 )
-        },
-        yyyy: function( string, dateObject ) {
-
-            // If there's a string, then the length is always 4.
-            // Otherwise return the selected year.
-            return string ? 4 : dateObject.year
-        },
-
-        // Create an array by splitting the formatting string passed.
-        toArray: function( formatString ) { return formatString.split( /(d{1,4}|m{1,4}|y{4}|yy|!.)/g ) },
-
-        // Format an object into a string using the formatting options.
-        toString: function ( formatString, itemObject ) {
-            var calendar = this
-            return calendar.formats.toArray( formatString ).map( function( label ) {
-                return _.trigger( calendar.formats[ label ], calendar, [ 0, itemObject ] ) || label.replace( /^!/, '' )
-            }).join( '' )
-        }
-    }
-})() //DatePicker.prototype.formats
-
-
-
-
-/**
- * Check if two date units are the exact.
- */
-DatePicker.prototype.isDateExact = function( one, two ) {
-
-    var calendar = this
-
-    // When we’re working with weekdays, do a direct comparison.
-    if (
-        ( _.isInteger( one ) && _.isInteger( two ) ) ||
-        ( typeof one == 'boolean' && typeof two == 'boolean' )
-     ) {
-        return one === two
-    }
-
-    // When we’re working with date representations, compare the “pick” value.
-    if (
-        ( _.isDate( one ) || $.isArray( one ) ) &&
-        ( _.isDate( two ) || $.isArray( two ) )
-    ) {
-        return calendar.create( one ).pick === calendar.create( two ).pick
-    }
-
-    // When we’re working with range objects, compare the “from” and “to”.
-    if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) {
-        return calendar.isDateExact( one.from, two.from ) && calendar.isDateExact( one.to, two.to )
-    }
-
-    return false
-}
-
-
-/**
- * Check if two date units overlap.
- */
-DatePicker.prototype.isDateOverlap = function( one, two ) {
-
-    var calendar = this,
-        firstDay = calendar.settings.firstDay ? 1 : 0
-
-    // When we’re working with a weekday index, compare the days.
-    if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) {
-        one = one % 7 + firstDay
-        return one === calendar.create( two ).day + 1
-    }
-    if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) {
-        two = two % 7 + firstDay
-        return two === calendar.create( one ).day + 1
-    }
-
-    // When we’re working with range objects, check if the ranges overlap.
-    if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) {
-        return calendar.overlapRanges( one, two )
-    }
-
-    return false
-}
-
-
-/**
- * Flip the “enabled” state.
- */
-DatePicker.prototype.flipEnable = function(val) {
-    var itemObject = this.item
-    itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1)
-}
-
-
-/**
- * Mark a collection of dates as “disabled”.
- */
-DatePicker.prototype.deactivate = function( type, datesToDisable ) {
-
-    var calendar = this,
-        disabledItems = calendar.item.disable.slice(0)
-
-
-    // If we’re flipping, that’s all we need to do.
-    if ( datesToDisable == 'flip' ) {
-        calendar.flipEnable()
-    }
-
-    else if ( datesToDisable === false ) {
-        calendar.flipEnable(1)
-        disabledItems = []
-    }
-
-    else if ( datesToDisable === true ) {
-        calendar.flipEnable(-1)
-        disabledItems = []
-    }
-
-    // Otherwise go through the dates to disable.
-    else {
-
-        datesToDisable.map(function( unitToDisable ) {
-
-            var matchFound
-
-            // When we have disabled items, check for matches.
-            // If something is matched, immediately break out.
-            for ( var index = 0; index < disabledItems.length; index += 1 ) {
-                if ( calendar.isDateExact( unitToDisable, disabledItems[index] ) ) {
-                    matchFound = true
-                    break
-                }
-            }
-
-            // If nothing was found, add the validated unit to the collection.
-            if ( !matchFound ) {
-                if (
-                    _.isInteger( unitToDisable ) ||
-                    _.isDate( unitToDisable ) ||
-                    $.isArray( unitToDisable ) ||
-                    ( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to )
-                ) {
-                    disabledItems.push( unitToDisable )
-                }
-            }
-        })
-    }
-
-    // Return the updated collection.
-    return disabledItems
-} //DatePicker.prototype.deactivate
-
-
-/**
- * Mark a collection of dates as “enabled”.
- */
-DatePicker.prototype.activate = function( type, datesToEnable ) {
-
-    var calendar = this,
-        disabledItems = calendar.item.disable,
-        disabledItemsCount = disabledItems.length
-
-    // If we’re flipping, that’s all we need to do.
-    if ( datesToEnable == 'flip' ) {
-        calendar.flipEnable()
-    }
-
-    else if ( datesToEnable === true ) {
-        calendar.flipEnable(1)
-        disabledItems = []
-    }
-
-    else if ( datesToEnable === false ) {
-        calendar.flipEnable(-1)
-        disabledItems = []
-    }
-
-    // Otherwise go through the disabled dates.
-    else {
-
-        datesToEnable.map(function( unitToEnable ) {
-
-            var matchFound,
-                disabledUnit,
-                index,
-                isExactRange
-
-            // Go through the disabled items and try to find a match.
-            for ( index = 0; index < disabledItemsCount; index += 1 ) {
-
-                disabledUnit = disabledItems[index]
-
-                // When an exact match is found, remove it from the collection.
-                if ( calendar.isDateExact( disabledUnit, unitToEnable ) ) {
-                    matchFound = disabledItems[index] = null
-                    isExactRange = true
-                    break
-                }
-
-                // When an overlapped match is found, add the “inverted” state to it.
-                else if ( calendar.isDateOverlap( disabledUnit, unitToEnable ) ) {
-                    if ( $.isPlainObject( unitToEnable ) ) {
-                        unitToEnable.inverted = true
-                        matchFound = unitToEnable
-                    }
-                    else if ( $.isArray( unitToEnable ) ) {
-                        matchFound = unitToEnable
-                        if ( !matchFound[3] ) matchFound.push( 'inverted' )
-                    }
-                    else if ( _.isDate( unitToEnable ) ) {
-                        matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ]
-                    }
-                    break
-                }
-            }
-
-            // If a match was found, remove a previous duplicate entry.
-            if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) {
-                if ( calendar.isDateExact( disabledItems[index], unitToEnable ) ) {
-                    disabledItems[index] = null
-                    break
-                }
-            }
-
-            // In the event that we’re dealing with an exact range of dates,
-            // make sure there are no “inverted” dates because of it.
-            if ( isExactRange ) for ( index = 0; index < disabledItemsCount; index += 1 ) {
-                if ( calendar.isDateOverlap( disabledItems[index], unitToEnable ) ) {
-                    disabledItems[index] = null
-                    break
-                }
-            }
-
-            // If something is still matched, add it into the collection.
-            if ( matchFound ) {
-                disabledItems.push( matchFound )
-            }
-        })
-    }
-
-    // Return the updated collection.
-    return disabledItems.filter(function( val ) { return val != null })
-} //DatePicker.prototype.activate
-
-
-/**
- * Create a string for the nodes in the picker.
- */
-DatePicker.prototype.nodes = function( isOpen ) {
-
-    var
-        calendar = this,
-        settings = calendar.settings,
-        calendarItem = calendar.item,
-        nowObject = calendarItem.now,
-        selectedObject = calendarItem.select,
-        highlightedObject = calendarItem.highlight,
-        viewsetObject = calendarItem.view,
-        disabledCollection = calendarItem.disable,
-        minLimitObject = calendarItem.min,
-        maxLimitObject = calendarItem.max,
-
-
-        // Create the calendar table head using a copy of weekday labels collection.
-        // * We do a copy so we don't mutate the original array.
-        tableHead = (function( collection, fullCollection ) {
-
-            // If the first day should be Monday, move Sunday to the end.
-            if ( settings.firstDay ) {
-                collection.push( collection.shift() )
-                fullCollection.push( fullCollection.shift() )
-            }
-
-            // Create and return the table head group.
-            return _.node(
-                'thead',
-                _.node(
-                    'tr',
-                    _.group({
-                        min: 0,
-                        max: DAYS_IN_WEEK - 1,
-                        i: 1,
-                        node: 'th',
-                        item: function( counter ) {
-                            return [
-                                collection[ counter ],
-                                settings.klass.weekdays,
-                                'scope=col title="' + fullCollection[ counter ] + '"'
-                            ]
-                        }
-                    })
-                )
-            ) //endreturn
-
-        // Materialize modified
-        })( ( settings.showWeekdaysFull ? settings.weekdaysFull : settings.weekdaysLetter ).slice( 0 ), settings.weekdaysFull.slice( 0 ) ), //tableHead
-
-
-        // Create the nav for next/prev month.
-        createMonthNav = function( next ) {
-
-            // Otherwise, return the created month tag.
-            return _.node(
-                'div',
-                ' ',
-                settings.klass[ 'nav' + ( next ? 'Next' : 'Prev' ) ] + (
-
-                    // If the focused month is outside the range, disabled the button.
-                    ( next && viewsetObject.year >= maxLimitObject.year && viewsetObject.month >= maxLimitObject.month ) ||
-                    ( !next && viewsetObject.year <= minLimitObject.year && viewsetObject.month <= minLimitObject.month ) ?
-                    ' ' + settings.klass.navDisabled : ''
-                ),
-                'data-nav=' + ( next || -1 ) + ' ' +
-                _.ariaAttr({
-                    role: 'button',
-                    controls: calendar.$node[0].id + '_table'
-                }) + ' ' +
-                'title="' + (next ? settings.labelMonthNext : settings.labelMonthPrev ) + '"'
-            ) //endreturn
-        }, //createMonthNav
-
-
-        // Create the month label.
-        //Materialize modified
-        createMonthLabel = function(override) {
-
-            var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull
-
-             // Materialize modified
-            if (override == "short_months") {
-              monthsCollection = settings.monthsShort;
-            }
-
-            // If there are months to select, add a dropdown menu.
-            if ( settings.selectMonths  && override == undefined) {
-
-                return _.node( 'select',
-                    _.group({
-                        min: 0,
-                        max: 11,
-                        i: 1,
-                        node: 'option',
-                        item: function( loopedMonth ) {
-
-                            return [
-
-                                // The looped month and no classes.
-                                monthsCollection[ loopedMonth ], 0,
-
-                                // Set the value and selected index.
-                                'value=' + loopedMonth +
-                                ( viewsetObject.month == loopedMonth ? ' selected' : '' ) +
-                                (
-                                    (
-                                        ( viewsetObject.year == minLimitObject.year && loopedMonth < minLimitObject.month ) ||
-                                        ( viewsetObject.year == maxLimitObject.year && loopedMonth > maxLimitObject.month )
-                                    ) ?
-                                    ' disabled' : ''
-                                )
-                            ]
-                        }
-                    }),
-                    settings.klass.selectMonth + ' browser-default',
-                    ( isOpen ? '' : 'disabled' ) + ' ' +
-                    _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' +
-                    'title="' + settings.labelMonthSelect + '"'
-                )
-            }
-
-            // Materialize modified
-            if (override == "short_months")
-                if (selectedObject != null)
-                return _.node( 'div', monthsCollection[ selectedObject.month ] );
-                else return _.node( 'div', monthsCollection[ viewsetObject.month ] );
-
-            // If there's a need for a month selector
-            return _.node( 'div', monthsCollection[ viewsetObject.month ], settings.klass.month )
-        }, //createMonthLabel
-
-
-        // Create the year label.
-        // Materialize modified
-        createYearLabel = function(override) {
-
-            var focusedYear = viewsetObject.year,
-
-            // If years selector is set to a literal "true", set it to 5. Otherwise
-            // divide in half to get half before and half after focused year.
-            numberYears = settings.selectYears === true ? 5 : ~~( settings.selectYears / 2 )
-
-            // If there are years to select, add a dropdown menu.
-            if ( numberYears ) {
-
-                var
-                    minYear = minLimitObject.year,
-                    maxYear = maxLimitObject.year,
-                    lowestYear = focusedYear - numberYears,
-                    highestYear = focusedYear + numberYears
-
-                // If the min year is greater than the lowest year, increase the highest year
-                // by the difference and set the lowest year to the min year.
-                if ( minYear > lowestYear ) {
-                    highestYear += minYear - lowestYear
-                    lowestYear = minYear
-                }
-
-                // If the max year is less than the highest year, decrease the lowest year
-                // by the lower of the two: available and needed years. Then set the
-                // highest year to the max year.
-                if ( maxYear < highestYear ) {
-
-                    var availableYears = lowestYear - minYear,
-                        neededYears = highestYear - maxYear
-
-                    lowestYear -= availableYears > neededYears ? neededYears : availableYears
-                    highestYear = maxYear
-                }
-
-                if ( settings.selectYears  && override == undefined ) {
-                    return _.node( 'select',
-                        _.group({
-                            min: lowestYear,
-                            max: highestYear,
-                            i: 1,
-                            node: 'option',
-                            item: function( loopedYear ) {
-                                return [
-
-                                    // The looped year and no classes.
-                                    loopedYear, 0,
-
-                                    // Set the value and selected index.
-                                    'value=' + loopedYear + ( focusedYear == loopedYear ? ' selected' : '' )
-                                ]
-                            }
-                        }),
-                        settings.klass.selectYear + ' browser-default',
-                        ( isOpen ? '' : 'disabled' ) + ' ' + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' +
-                        'title="' + settings.labelYearSelect + '"'
-                    )
-                }
-            }
-
-            // Materialize modified
-            if (override == "raw")
-                return _.node( 'div', focusedYear )
-
-            // Otherwise just return the year focused
-            return _.node( 'div', focusedYear, settings.klass.year )
-        } //createYearLabel
-
-
-        // Materialize modified
-        createDayLabel = function() {
-                if (selectedObject != null)
-                    return _.node( 'div', selectedObject.date)
-                else return _.node( 'div', nowObject.date)
-            }
-        createWeekdayLabel = function() {
-            var display_day;
-
-            if (selectedObject != null)
-                display_day = selectedObject.day;
-            else
-                display_day = nowObject.day;
-            var weekday = settings.weekdaysFull[ display_day ]
-            return weekday
-        }
-
-
-    // Create and return the entire calendar.
-return _.node(
-        // Date presentation View
-        'div',
-            _.node(
-                'div',
-                createWeekdayLabel(),
-                "picker__weekday-display"
-            )+
-            _.node(
-                // Div for short Month
-                'div',
-                createMonthLabel("short_months"),
-                settings.klass.month_display
-            )+
-            _.node(
-                // Div for Day
-                'div',
-                createDayLabel() ,
-                settings.klass.day_display
-            )+
-            _.node(
-                // Div for Year
-                'div',
-                createYearLabel("raw") ,
-                settings.klass.year_display
-            ),
-        settings.klass.date_display
-    )+
-    // Calendar container
-    _.node('div',
-        _.node('div',
-        ( settings.selectYears ?  createMonthLabel() + createYearLabel() : createMonthLabel() + createYearLabel() ) +
-        createMonthNav() + createMonthNav( 1 ),
-        settings.klass.header
-    ) + _.node(
-        'table',
-        tableHead +
-        _.node(
-            'tbody',
-            _.group({
-                min: 0,
-                max: WEEKS_IN_CALENDAR - 1,
-                i: 1,
-                node: 'tr',
-                item: function( rowCounter ) {
-
-                    // If Monday is the first day and the month starts on Sunday, shift the date back a week.
-                    var shiftDateBy = settings.firstDay && calendar.create([ viewsetObject.year, viewsetObject.month, 1 ]).day === 0 ? -7 : 0
-
-                    return [
-                        _.group({
-                            min: DAYS_IN_WEEK * rowCounter - viewsetObject.day + shiftDateBy + 1, // Add 1 for weekday 0index
-                            max: function() {
-                                return this.min + DAYS_IN_WEEK - 1
-                            },
-                            i: 1,
-                            node: 'td',
-                            item: function( targetDate ) {
-
-                                // Convert the time date from a relative date to a target date.
-                                targetDate = calendar.create([ viewsetObject.year, viewsetObject.month, targetDate + ( settings.firstDay ? 1 : 0 ) ])
-
-                                var isSelected = selectedObject && selectedObject.pick == targetDate.pick,
-                                    isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick,
-                                    isDisabled = disabledCollection && calendar.disabled( targetDate ) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick,
-                                    formattedDate = _.trigger( calendar.formats.toString, calendar, [ settings.format, targetDate ] )
-
-                                return [
-                                    _.node(
-                                        'div',
-                                        targetDate.date,
-                                        (function( klasses ) {
-
-                                            // Add the `infocus` or `outfocus` classes based on month in view.
-                                            klasses.push( viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus )
-
-                                            // Add the `today` class if needed.
-                                            if ( nowObject.pick == targetDate.pick ) {
-                                                klasses.push( settings.klass.now )
-                                            }
-
-                                            // Add the `selected` class if something's selected and the time matches.
-                                            if ( isSelected ) {
-                                                klasses.push( settings.klass.selected )
-                                            }
-
-                                            // Add the `highlighted` class if something's highlighted and the time matches.
-                                            if ( isHighlighted ) {
-                                                klasses.push( settings.klass.highlighted )
-                                            }
-
-                                            // Add the `disabled` class if something's disabled and the object matches.
-                                            if ( isDisabled ) {
-                                                klasses.push( settings.klass.disabled )
-                                            }
-
-                                            return klasses.join( ' ' )
-                                        })([ settings.klass.day ]),
-                                        'data-pick=' + targetDate.pick + ' ' + _.ariaAttr({
-                                            role: 'gridcell',
-                                            label: formattedDate,
-                                            selected: isSelected && calendar.$node.val() === formattedDate ? true : null,
-                                            activedescendant: isHighlighted ? true : null,
-                                            disabled: isDisabled ? true : null
-                                        })
-                                    ),
-                                    '',
-                                    _.ariaAttr({ role: 'presentation' })
-                                ] //endreturn
-                            }
-                        })
-                    ] //endreturn
-                }
-            })
-        ),
-        settings.klass.table,
-        'id="' + calendar.$node[0].id + '_table' + '" ' + _.ariaAttr({
-            role: 'grid',
-            controls: calendar.$node[0].id,
-            readonly: true
-        })
-    )
-    , settings.klass.calendar_container) // end calendar
-
-     +
-
-    // * For Firefox forms to submit, make sure to set the buttons’ `type` attributes as “button”.
-    _.node(
-        'div',
-        _.node( 'button', settings.today, "btn-flat picker__today",
-            'type=button data-pick=' + nowObject.pick +
-            ( isOpen && !calendar.disabled(nowObject) ? '' : ' disabled' ) + ' ' +
-            _.ariaAttr({ controls: calendar.$node[0].id }) ) +
-        _.node( 'button', settings.clear, "btn-flat picker__clear",
-            'type=button data-clear=1' +
-            ( isOpen ? '' : ' disabled' ) + ' ' +
-            _.ariaAttr({ controls: calendar.$node[0].id }) ) +
-        _.node('button', settings.close, "btn-flat picker__close",
-            'type=button data-close=true ' +
-            ( isOpen ? '' : ' disabled' ) + ' ' +
-            _.ariaAttr({ controls: calendar.$node[0].id }) ),
-        settings.klass.footer
-    ) //endreturn
-} //DatePicker.prototype.nodes
-
-
-
-
-/**
- * The date picker defaults.
- */
-DatePicker.defaults = (function( prefix ) {
-
-    return {
-
-        // The title label to use for the month nav buttons
-        labelMonthNext: 'Next month',
-        labelMonthPrev: 'Previous month',
-
-        // The title label to use for the dropdown selectors
-        labelMonthSelect: 'Select a month',
-        labelYearSelect: 'Select a year',
-
-        // Months and weekdays
-        monthsFull: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ],
-        monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ],
-        weekdaysFull: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ],
-        weekdaysShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ],
-
-        // Materialize modified
-        weekdaysLetter: [ 'S', 'M', 'T', 'W', 'T', 'F', 'S' ],
-
-        // Today and clear
-        today: 'Today',
-        clear: 'Clear',
-        close: 'Close',
-
-        // The format to show on the `input` element
-        format: 'd mmmm, yyyy',
-
-        // Classes
-        klass: {
-
-            table: prefix + 'table',
-
-            header: prefix + 'header',
-
-
-            // Materialize Added klasses
-            date_display: prefix + 'date-display',
-            day_display: prefix + 'day-display',
-            month_display: prefix + 'month-display',
-            year_display: prefix + 'year-display',
-            calendar_container: prefix + 'calendar-container',
-            // end
-
-
-
-            navPrev: prefix + 'nav--prev',
-            navNext: prefix + 'nav--next',
-            navDisabled: prefix + 'nav--disabled',
-
-            month: prefix + 'month',
-            year: prefix + 'year',
-
-            selectMonth: prefix + 'select--month',
-            selectYear: prefix + 'select--year',
-
-            weekdays: prefix + 'weekday',
-
-            day: prefix + 'day',
-            disabled: prefix + 'day--disabled',
-            selected: prefix + 'day--selected',
-            highlighted: prefix + 'day--highlighted',
-            now: prefix + 'day--today',
-            infocus: prefix + 'day--infocus',
-            outfocus: prefix + 'day--outfocus',
-
-            footer: prefix + 'footer',
-
-            buttonClear: prefix + 'button--clear',
-            buttonToday: prefix + 'button--today',
-            buttonClose: prefix + 'button--close'
-        }
-    }
-})( Picker.klasses().picker + '__' )
-
-
-
-
-
-/**
- * Extend the picker to add the date picker.
- */
-Picker.extend( 'pickadate', DatePicker )
-
-
-}));
-
-
-;(function ($) {
-
-  $.fn.characterCounter = function(){
-    return this.each(function(){
-      var $input = $(this);
-      var $counterElement = $input.parent().find('span[class="character-counter"]');
-
-      // character counter has already been added appended to the parent container
-      if ($counterElement.length) {
-        return;
-      }
-
-      var itHasLengthAttribute = $input.attr('data-length') !== undefined;
-
-      if(itHasLengthAttribute){
-        $input.on('input', updateCounter);
-        $input.on('focus', updateCounter);
-        $input.on('blur', removeCounterElement);
-
-        addCounterElement($input);
-      }
-
-    });
-  };
-
-  function updateCounter(){
-    var maxLength     = +$(this).attr('data-length'),
-    actualLength      = +$(this).val().length,
-    isValidLength     = actualLength <= maxLength;
-
-    $(this).parent().find('span[class="character-counter"]')
-                    .html( actualLength + '/' + maxLength);
-
-    addInputStyle(isValidLength, $(this));
-  }
-
-  function addCounterElement($input) {
-    var $counterElement = $input.parent().find('span[class="character-counter"]');
-
-    if ($counterElement.length) {
-      return;
-    }
-
-    $counterElement = $('<span/>')
-                        .addClass('character-counter')
-                        .css('float','right')
-                        .css('font-size','12px')
-                        .css('height', 1);
-
-    $input.parent().append($counterElement);
-  }
-
-  function removeCounterElement(){
-    $(this).parent().find('span[class="character-counter"]').html('');
-  }
-
-  function addInputStyle(isValidLength, $input){
-    var inputHasInvalidClass = $input.hasClass('invalid');
-    if (isValidLength && inputHasInvalidClass) {
-      $input.removeClass('invalid');
-    }
-    else if(!isValidLength && !inputHasInvalidClass){
-      $input.removeClass('valid');
-      $input.addClass('invalid');
-    }
-  }
-
-  $(document).ready(function(){
-    $('input, textarea').characterCounter();
-  });
-
-}( jQuery ));
-;(function ($) {
-
-  var methods = {
-
-    init : function(options) {
-      var defaults = {
-        duration: 200, // ms
-        dist: -100, // zoom scale TODO: make this more intuitive as an option
-        shift: 0, // spacing for center image
-        padding: 0, // Padding between non center items
-        fullWidth: false, // Change to full width styles
-        indicators: false, // Toggle indicators
-        noWrap: false, // Don't wrap around and cycle through items.
-        onCycleTo: null // Callback for when a new slide is cycled to.
-      };
-      options = $.extend(defaults, options);
-
-      return this.each(function() {
-
-        var images, item_width, item_height, offset, center, pressed, dim, count,
-            reference, referenceY, amplitude, target, velocity,
-            xform, frame, timestamp, ticker, dragged, vertical_dragged;
-        var $indicators = $('<ul class="indicators"></ul>');
-
-
-        // Initialize
-        var view = $(this);
-        var showIndicators = view.attr('data-indicators') || options.indicators;
-
-        // Don't double initialize.
-        if (view.hasClass('initialized')) {
-          // Redraw carousel.
-          $(this).trigger('carouselNext', [0.000001]);
-          return true;
-        }
-
-
-        // Options
-        if (options.fullWidth) {
-          options.dist = 0;
-          var firstImage = view.find('.carousel-item img').first();
-          if (firstImage.length) {
-            imageHeight = firstImage.on('load', function(){
-              view.css('height', $(this).height());
-            });
-          } else {
-            imageHeight = view.find('.carousel-item').first().height();
-            view.css('height', imageHeight);
-          }
-
-          // Offset fixed items when indicators.
-          if (showIndicators) {
-            view.find('.carousel-fixed-item').addClass('with-indicators');
-          }
-        }
-
-
-        view.addClass('initialized');
-        pressed = false;
-        offset = target = 0;
-        images = [];
-        item_width = view.find('.carousel-item').first().innerWidth();
-        item_height = view.find('.carousel-item').first().innerHeight();
-        dim = item_width * 2 + options.padding;
-
-        view.find('.carousel-item').each(function (i) {
-          images.push($(this)[0]);
-          if (showIndicators) {
-            var $indicator = $('<li class="indicator-item"></li>');
-
-            // Add active to first by default.
-            if (i === 0) {
-              $indicator.addClass('active');
-            }
-
-            // Handle clicks on indicators.
-            $indicator.click(function (e) {
-              e.stopPropagation();
-
-              var index = $(this).index();
-              cycleTo(index);
-            });
-            $indicators.append($indicator);
-          }
-        });
-
-        if (showIndicators) {
-          view.append($indicators);
-        }
-        count = images.length;
-
-
-        function setupEvents() {
-          if (typeof window.ontouchstart !== 'undefined') {
-            view[0].addEventListener('touchstart', tap);
-            view[0].addEventListener('touchmove', drag);
-            view[0].addEventListener('touchend', release);
-          }
-          view[0].addEventListener('mousedown', tap);
-          view[0].addEventListener('mousemove', drag);
-          view[0].addEventListener('mouseup', release);
-          view[0].addEventListener('mouseleave', release);
-          view[0].addEventListener('click', click);
-        }
-
-        function xpos(e) {
-          // touch event
-          if (e.targetTouches && (e.targetTouches.length >= 1)) {
-            return e.targetTouches[0].clientX;
-          }
-
-          // mouse event
-          return e.clientX;
-        }
-
-        function ypos(e) {
-          // touch event
-          if (e.targetTouches && (e.targetTouches.length >= 1)) {
-            return e.targetTouches[0].clientY;
-          }
-
-          // mouse event
-          return e.clientY;
-        }
-
-        function wrap(x) {
-          return (x >= count) ? (x % count) : (x < 0) ? wrap(count + (x % count)) : x;
-        }
-
-        function scroll(x) {
-          var i, half, delta, dir, tween, el, alignment, xTranslation;
-          var lastCenter = center;
-
-          offset = (typeof x === 'number') ? x : offset;
-          center = Math.floor((offset + dim / 2) / dim);
-          delta = offset - center * dim;
-          dir = (delta < 0) ? 1 : -1;
-          tween = -dir * delta * 2 / dim;
-          half = count >> 1;
-
-          if (!options.fullWidth) {
-            alignment = 'translateX(' + (view[0].clientWidth - item_width) / 2 + 'px) ';
-            alignment += 'translateY(' + (view[0].clientHeight - item_height) / 2 + 'px)';
-          } else {
-            alignment = 'translateX(0)';
-          }
-
-          // Set indicator active
-          if (showIndicators) {
-            var diff = (center % count);
-            var activeIndicator = $indicators.find('.indicator-item.active');
-            if (activeIndicator.index() !== diff) {
-              activeIndicator.removeClass('active');
-              $indicators.find('.indicator-item').eq(diff).addClass('active');
-            }
-          }
-
-          // center
-          // Don't show wrapped items.
-          if (!options.noWrap || (center >= 0 && center < count)) {
-            el = images[wrap(center)];
-
-            // Add active class to center item.
-            if (!$(el).hasClass('active')) {
-              view.find('.carousel-item').removeClass('active');
-              $(el).addClass('active');
-            }
-            el.style[xform] = alignment +
-              ' translateX(' + (-delta / 2) + 'px)' +
-              ' translateX(' + (dir * options.shift * tween * i) + 'px)' +
-              ' translateZ(' + (options.dist * tween) + 'px)';
-            el.style.zIndex = 0;
-            if (options.fullWidth) { tweenedOpacity = 1; }
-            else { tweenedOpacity = 1 - 0.2 * tween; }
-            el.style.opacity = tweenedOpacity;
-            el.style.display = 'block';
-          }
-
-          for (i = 1; i <= half; ++i) {
-            // right side
-            if (options.fullWidth) {
-              zTranslation = options.dist;
-              tweenedOpacity = (i === half && delta < 0) ? 1 - tween : 1;
-            } else {
-              zTranslation = options.dist * (i * 2 + tween * dir);
-              tweenedOpacity = 1 - 0.2 * (i * 2 + tween * dir);
-            }
-            // Don't show wrapped items.
-            if (!options.noWrap || center + i < count) {
-              el = images[wrap(center + i)];
-              el.style[xform] = alignment +
-                ' translateX(' + (options.shift + (dim * i - delta) / 2) + 'px)' +
-                ' translateZ(' + zTranslation + 'px)';
-              el.style.zIndex = -i;
-              el.style.opacity = tweenedOpacity;
-              el.style.display = 'block';
-            }
-
-
-            // left side
-            if (options.fullWidth) {
-              zTranslation = options.dist;
-              tweenedOpacity = (i === half && delta > 0) ? 1 - tween : 1;
-            } else {
-              zTranslation = options.dist * (i * 2 - tween * dir);
-              tweenedOpacity = 1 - 0.2 * (i * 2 - tween * dir);
-            }
-            // Don't show wrapped items.
-            if (!options.noWrap || center - i >= 0) {
-              el = images[wrap(center - i)];
-              el.style[xform] = alignment +
-                ' translateX(' + (-options.shift + (-dim * i - delta) / 2) + 'px)' +
-                ' translateZ(' + zTranslation + 'px)';
-              el.style.zIndex = -i;
-              el.style.opacity = tweenedOpacity;
-              el.style.display = 'block';
-            }
-          }
-
-          // center
-          // Don't show wrapped items.
-          if (!options.noWrap || (center >= 0 && center < count)) {
-            el = images[wrap(center)];
-            el.style[xform] = alignment +
-              ' translateX(' + (-delta / 2) + 'px)' +
-              ' translateX(' + (dir * options.shift * tween) + 'px)' +
-              ' translateZ(' + (options.dist * tween) + 'px)';
-            el.style.zIndex = 0;
-            if (options.fullWidth) { tweenedOpacity = 1; }
-            else { tweenedOpacity = 1 - 0.2 * tween; }
-            el.style.opacity = tweenedOpacity;
-            el.style.display = 'block';
-          }
-
-          // onCycleTo callback
-          if (lastCenter !== center &&
-              typeof(options.onCycleTo) === "function") {
-            var $curr_item = view.find('.carousel-item').eq(wrap(center));
-            options.onCycleTo.call(this, $curr_item, dragged);
-          }
-        }
-
-        function track() {
-          var now, elapsed, delta, v;
-
-          now = Date.now();
-          elapsed = now - timestamp;
-          timestamp = now;
-          delta = offset - frame;
-          frame = offset;
-
-          v = 1000 * delta / (1 + elapsed);
-          velocity = 0.8 * v + 0.2 * velocity;
-        }
-
-        function autoScroll() {
-          var elapsed, delta;
-
-          if (amplitude) {
-            elapsed = Date.now() - timestamp;
-            delta = amplitude * Math.exp(-elapsed / options.duration);
-            if (delta > 2 || delta < -2) {
-                scroll(target - delta);
-                requestAnimationFrame(autoScroll);
-            } else {
-                scroll(target);
-            }
-          }
-        }
-
-        function click(e) {
-          // Disable clicks if carousel was dragged.
-          if (dragged) {
-            e.preventDefault();
-            e.stopPropagation();
-            return false;
-
-          } else if (!options.fullWidth) {
-            var clickedIndex = $(e.target).closest('.carousel-item').index();
-            var diff = (center % count) - clickedIndex;
-
-            // Disable clicks if carousel was shifted by click
-            if (diff !== 0) {
-              e.preventDefault();
-              e.stopPropagation();
-            }
-            cycleTo(clickedIndex);
-          }
-        }
-
-        function cycleTo(n) {
-          var diff = (center % count) - n;
-
-          // Account for wraparound.
-          if (!options.noWrap) {
-            if (diff < 0) {
-              if (Math.abs(diff + count) < Math.abs(diff)) { diff += count; }
-
-            } else if (diff > 0) {
-              if (Math.abs(diff - count) < diff) { diff -= count; }
-            }
-          }
-
-          // Call prev or next accordingly.
-          if (diff < 0) {
-            view.trigger('carouselNext', [Math.abs(diff)]);
-
-          } else if (diff > 0) {
-            view.trigger('carouselPrev', [diff]);
-          }
-        }
-
-        function tap(e) {
-          pressed = true;
-          dragged = false;
-          vertical_dragged = false;
-          reference = xpos(e);
-          referenceY = ypos(e);
-
-          velocity = amplitude = 0;
-          frame = offset;
-          timestamp = Date.now();
-          clearInterval(ticker);
-          ticker = setInterval(track, 100);
-
-        }
-
-        function drag(e) {
-          var x, delta, deltaY;
-          if (pressed) {
-            x = xpos(e);
-            y = ypos(e);
-            delta = reference - x;
-            deltaY = Math.abs(referenceY - y);
-            if (deltaY < 30 && !vertical_dragged) {
-              // If vertical scrolling don't allow dragging.
-              if (delta > 2 || delta < -2) {
-                dragged = true;
-                reference = x;
-                scroll(offset + delta);
-              }
-
-            } else if (dragged) {
-              // If dragging don't allow vertical scroll.
-              e.preventDefault();
-              e.stopPropagation();
-              return false;
-
-            } else {
-              // Vertical scrolling.
-              vertical_dragged = true;
-            }
-          }
-
-          if (dragged) {
-            // If dragging don't allow vertical scroll.
-            e.preventDefault();
-            e.stopPropagation();
-            return false;
-          }
-        }
-
-        function release(e) {
-          if (pressed) {
-            pressed = false;
-          } else {
-            return;
-          }
-
-          clearInterval(ticker);
-          target = offset;
-          if (velocity > 10 || velocity < -10) {
-            amplitude = 0.9 * velocity;
-            target = offset + amplitude;
-          }
-          target = Math.round(target / dim) * dim;
-
-          // No wrap of items.
-          if (options.noWrap) {
-            if (target >= dim * (count - 1)) {
-              target = dim * (count - 1);
-            } else if (target < 0) {
-              target = 0;
-            }
-          }
-          amplitude = target - offset;
-          timestamp = Date.now();
-          requestAnimationFrame(autoScroll);
-
-          if (dragged) {
-            e.preventDefault();
-            e.stopPropagation();
-          }
-          return false;
-        }
-
-        xform = 'transform';
-        ['webkit', 'Moz', 'O', 'ms'].every(function (prefix) {
-          var e = prefix + 'Transform';
-          if (typeof document.body.style[e] !== 'undefined') {
-            xform = e;
-            return false;
-          }
-          return true;
-        });
-
-
-        $(window).on('resize.carousel', function() {
-          if (options.fullWidth) {
-            item_width = view.find('.carousel-item').first().innerWidth();
-            item_height = view.find('.carousel-item').first().innerHeight();
-            dim = item_width * 2 + options.padding;
-            offset = center * 2 * item_width;
-            target = offset;
-          } else {
-            scroll();
-          }
-        });
-
-        setupEvents();
-        scroll(offset);
-
-        $(this).on('carouselNext', function(e, n) {
-          if (n === undefined) {
-            n = 1;
-          }
-          target = (dim * Math.round(offset / dim)) + (dim * n);
-          if (offset !== target) {
-            amplitude = target - offset;
-            timestamp = Date.now();
-            requestAnimationFrame(autoScroll);
-          }
-        });
-
-        $(this).on('carouselPrev', function(e, n) {
-          if (n === undefined) {
-            n = 1;
-          }
-          target = (dim * Math.round(offset / dim)) - (dim * n);
-          if (offset !== target) {
-            amplitude = target - offset;
-            timestamp = Date.now();
-            requestAnimationFrame(autoScroll);
-          }
-        });
-
-        $(this).on('carouselSet', function(e, n) {
-          if (n === undefined) {
-            n = 0;
-          }
-          cycleTo(n);
-        });
-
-      });
-
-
-
-    },
-    next : function(n) {
-      $(this).trigger('carouselNext', [n]);
-    },
-    prev : function(n) {
-      $(this).trigger('carouselPrev', [n]);
-    },
-    set : function(n) {
-      $(this).trigger('carouselSet', [n]);
-    }
-  };
-
-
-    $.fn.carousel = function(methodOrOptions) {
-      if ( methods[methodOrOptions] ) {
-        return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
-      } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
-        // Default to "init"
-        return methods.init.apply( this, arguments );
-      } else {
-        $.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.carousel' );
-      }
-    }; // Plugin end
-}( jQuery ));
\ No newline at end of file
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/js/materialize.min.js b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/materialize/js/materialize.min.js
deleted file mode 100644 (file)
index 00c0d5f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*!
- * Materialize v0.98.0 (http://materializecss.com)
- * Copyright 2014-2015 Materialize
- * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE)
- */
-if("undefined"==typeof jQuery){var jQuery;jQuery="function"==typeof require?$=require("jquery"):$}jQuery.easing.jswing=jQuery.easing.swing,jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(a,b,c,d,e){return jQuery.easing[jQuery.easing.def](a,b,c,d,e)},easeInQuad:function(a,b,c,d,e){return d*(b/=e)*b+c},easeOutQuad:function(a,b,c,d,e){return-d*(b/=e)*(b-2)+c},easeInOutQuad:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b+c:-d/2*(--b*(b-2)-1)+c},easeInCubic:function(a,b,c,d,e){return d*(b/=e)*b*b+c},easeOutCubic:function(a,b,c,d,e){return d*((b=b/e-1)*b*b+1)+c},easeInOutCubic:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b+c:d/2*((b-=2)*b*b+2)+c},easeInQuart:function(a,b,c,d,e){return d*(b/=e)*b*b*b+c},easeOutQuart:function(a,b,c,d,e){return-d*((b=b/e-1)*b*b*b-1)+c},easeInOutQuart:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b+c:-d/2*((b-=2)*b*b*b-2)+c},easeInQuint:function(a,b,c,d,e){return d*(b/=e)*b*b*b*b+c},easeOutQuint:function(a,b,c,d,e){return d*((b=b/e-1)*b*b*b*b+1)+c},easeInOutQuint:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b*b+c:d/2*((b-=2)*b*b*b*b+2)+c},easeInSine:function(a,b,c,d,e){return-d*Math.cos(b/e*(Math.PI/2))+d+c},easeOutSine:function(a,b,c,d,e){return d*Math.sin(b/e*(Math.PI/2))+c},easeInOutSine:function(a,b,c,d,e){return-d/2*(Math.cos(Math.PI*b/e)-1)+c},easeInExpo:function(a,b,c,d,e){return 0==b?c:d*Math.pow(2,10*(b/e-1))+c},easeOutExpo:function(a,b,c,d,e){return b==e?c+d:d*(-Math.pow(2,-10*b/e)+1)+c},easeInOutExpo:function(a,b,c,d,e){return 0==b?c:b==e?c+d:(b/=e/2)<1?d/2*Math.pow(2,10*(b-1))+c:d/2*(-Math.pow(2,-10*--b)+2)+c},easeInCirc:function(a,b,c,d,e){return-d*(Math.sqrt(1-(b/=e)*b)-1)+c},easeOutCirc:function(a,b,c,d,e){return d*Math.sqrt(1-(b=b/e-1)*b)+c},easeInOutCirc:function(a,b,c,d,e){return(b/=e/2)<1?-d/2*(Math.sqrt(1-b*b)-1)+c:d/2*(Math.sqrt(1-(b-=2)*b)+1)+c},easeInElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(1==(b/=e))return c+d;if(g||(g=.3*e),h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*(2*Math.PI)/g))+c},easeOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(1==(b/=e))return c+d;if(g||(g=.3*e),h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*b)*Math.sin((b*e-f)*(2*Math.PI)/g)+d+c},easeInOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(2==(b/=e/2))return c+d;if(g||(g=e*(.3*1.5)),h<Math.abs(d)){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return b<1?-.5*(h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*(2*Math.PI)/g))+c:h*Math.pow(2,-10*(b-=1))*Math.sin((b*e-f)*(2*Math.PI)/g)*.5+d+c},easeInBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),d*(b/=e)*b*((f+1)*b-f)+c},easeOutBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),d*((b=b/e-1)*b*((f+1)*b+f)+1)+c},easeInOutBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),(b/=e/2)<1?d/2*(b*b*(((f*=1.525)+1)*b-f))+c:d/2*((b-=2)*b*(((f*=1.525)+1)*b+f)+2)+c},easeInBounce:function(a,b,c,d,e){return d-jQuery.easing.easeOutBounce(a,e-b,0,d,e)+c},easeOutBounce:function(a,b,c,d,e){return(b/=e)<1/2.75?d*(7.5625*b*b)+c:b<2/2.75?d*(7.5625*(b-=1.5/2.75)*b+.75)+c:b<2.5/2.75?d*(7.5625*(b-=2.25/2.75)*b+.9375)+c:d*(7.5625*(b-=2.625/2.75)*b+.984375)+c},easeInOutBounce:function(a,b,c,d,e){return b<e/2?.5*jQuery.easing.easeInBounce(a,2*b,0,d,e)+c:.5*jQuery.easing.easeOutBounce(a,2*b-e,0,d,e)+.5*d+c}}),jQuery.extend(jQuery.easing,{easeInOutMaterial:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b+c:d/4*((b-=2)*b*b+2)+c}}),jQuery.Velocity?console.log("Velocity is already loaded. You may be needlessly importing Velocity again; note that Materialize includes Velocity."):(!function(a){function b(a){var b=a.length,d=c.type(a);return"function"!==d&&!c.isWindow(a)&&(!(1!==a.nodeType||!b)||("array"===d||0===b||"number"==typeof b&&b>0&&b-1 in a))}if(!a.jQuery){var c=function(a,b){return new c.fn.init(a,b)};c.isWindow=function(a){return null!=a&&a==a.window},c.type=function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?e[g.call(a)]||"object":typeof a},c.isArray=Array.isArray||function(a){return"array"===c.type(a)},c.isPlainObject=function(a){var b;if(!a||"object"!==c.type(a)||a.nodeType||c.isWindow(a))return!1;try{if(a.constructor&&!f.call(a,"constructor")&&!f.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(d){return!1}for(b in a);return void 0===b||f.call(a,b)},c.each=function(a,c,d){var e,f=0,g=a.length,h=b(a);if(d){if(h)for(;g>f&&(e=c.apply(a[f],d),e!==!1);f++);else for(f in a)if(e=c.apply(a[f],d),e===!1)break}else if(h)for(;g>f&&(e=c.call(a[f],f,a[f]),e!==!1);f++);else for(f in a)if(e=c.call(a[f],f,a[f]),e===!1)break;return a},c.data=function(a,b,e){if(void 0===e){var f=a[c.expando],g=f&&d[f];if(void 0===b)return g;if(g&&b in g)return g[b]}else if(void 0!==b){var f=a[c.expando]||(a[c.expando]=++c.uuid);return d[f]=d[f]||{},d[f][b]=e,e}},c.removeData=function(a,b){var e=a[c.expando],f=e&&d[e];f&&c.each(b,function(a,b){delete f[b]})},c.extend=function(){var a,b,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;for("boolean"==typeof h&&(k=h,h=arguments[i]||{},i++),"object"!=typeof h&&"function"!==c.type(h)&&(h={}),i===j&&(h=this,i--);j>i;i++)if(null!=(f=arguments[i]))for(e in f)a=h[e],d=f[e],h!==d&&(k&&d&&(c.isPlainObject(d)||(b=c.isArray(d)))?(b?(b=!1,g=a&&c.isArray(a)?a:[]):g=a&&c.isPlainObject(a)?a:{},h[e]=c.extend(k,g,d)):void 0!==d&&(h[e]=d));return h},c.queue=function(a,d,e){function f(a,c){var d=c||[];return null!=a&&(b(Object(a))?!function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;)a[e++]=b[d++];if(c!==c)for(;void 0!==b[d];)a[e++]=b[d++];return a.length=e,a}(d,"string"==typeof a?[a]:a):[].push.call(d,a)),d}if(a){d=(d||"fx")+"queue";var g=c.data(a,d);return e?(!g||c.isArray(e)?g=c.data(a,d,f(e)):g.push(e),g):g||[]}},c.dequeue=function(a,b){c.each(a.nodeType?[a]:a,function(a,d){b=b||"fx";var e=c.queue(d,b),f=e.shift();"inprogress"===f&&(f=e.shift()),f&&("fx"===b&&e.unshift("inprogress"),f.call(d,function(){c.dequeue(d,b)}))})},c.fn=c.prototype={init:function(a){if(a.nodeType)return this[0]=a,this;throw new Error("Not a DOM node.")},offset:function(){var b=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:b.top+(a.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:b.left+(a.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function a(){for(var a=this.offsetParent||document;a&&"html"===!a.nodeType.toLowerCase&&"static"===a.style.position;)a=a.offsetParent;return a||document}var b=this[0],a=a.apply(b),d=this.offset(),e=/^(?:body|html)$/i.test(a.nodeName)?{top:0,left:0}:c(a).offset();return d.top-=parseFloat(b.style.marginTop)||0,d.left-=parseFloat(b.style.marginLeft)||0,a.style&&(e.top+=parseFloat(a.style.borderTopWidth)||0,e.left+=parseFloat(a.style.borderLeftWidth)||0),{top:d.top-e.top,left:d.left-e.left}}};var d={};c.expando="velocity"+(new Date).getTime(),c.uuid=0;for(var e={},f=e.hasOwnProperty,g=e.toString,h="Boolean Number String Function Array Date RegExp Object Error".split(" "),i=0;i<h.length;i++)e["[object "+h[i]+"]"]=h[i].toLowerCase();c.fn.init.prototype=c.fn,a.Velocity={Utilities:c}}}(window),function(a){"object"==typeof module&&"object"==typeof module.exports?module.exports=a():"function"==typeof define&&define.amd?define(a):a()}(function(){return function(a,b,c,d){function e(a){for(var b=-1,c=a?a.length:0,d=[];++b<c;){var e=a[b];e&&d.push(e)}return d}function f(a){return p.isWrapped(a)?a=[].slice.call(a):p.isNode(a)&&(a=[a]),a}function g(a){var b=m.data(a,"velocity");return null===b?d:b}function h(a){return function(b){return Math.round(b*a)*(1/a)}}function i(a,c,d,e){function f(a,b){return 1-3*b+3*a}function g(a,b){return 3*b-6*a}function h(a){return 3*a}function i(a,b,c){return((f(b,c)*a+g(b,c))*a+h(b))*a}function j(a,b,c){return 3*f(b,c)*a*a+2*g(b,c)*a+h(b)}function k(b,c){for(var e=0;p>e;++e){var f=j(c,a,d);if(0===f)return c;var g=i(c,a,d)-b;c-=g/f}return c}function l(){for(var b=0;t>b;++b)x[b]=i(b*u,a,d)}function m(b,c,e){var f,g,h=0;do g=c+(e-c)/2,f=i(g,a,d)-b,f>0?e=g:c=g;while(Math.abs(f)>r&&++h<s);return g}function n(b){for(var c=0,e=1,f=t-1;e!=f&&x[e]<=b;++e)c+=u;--e;var g=(b-x[e])/(x[e+1]-x[e]),h=c+g*u,i=j(h,a,d);return i>=q?k(b,h):0==i?h:m(b,c,c+u)}function o(){y=!0,(a!=c||d!=e)&&l()}var p=4,q=.001,r=1e-7,s=10,t=11,u=1/(t-1),v="Float32Array"in b;if(4!==arguments.length)return!1;for(var w=0;4>w;++w)if("number"!=typeof arguments[w]||isNaN(arguments[w])||!isFinite(arguments[w]))return!1;a=Math.min(a,1),d=Math.min(d,1),a=Math.max(a,0),d=Math.max(d,0);var x=v?new Float32Array(t):new Array(t),y=!1,z=function(b){return y||o(),a===c&&d===e?b:0===b?0:1===b?1:i(n(b),c,e)};z.getControlPoints=function(){return[{x:a,y:c},{x:d,y:e}]};var A="generateBezier("+[a,c,d,e]+")";return z.toString=function(){return A},z}function j(a,b){var c=a;return p.isString(a)?t.Easings[a]||(c=!1):c=p.isArray(a)&&1===a.length?h.apply(null,a):p.isArray(a)&&2===a.length?u.apply(null,a.concat([b])):!(!p.isArray(a)||4!==a.length)&&i.apply(null,a),c===!1&&(c=t.Easings[t.defaults.easing]?t.defaults.easing:s),c}function k(a){if(a){var b=(new Date).getTime(),c=t.State.calls.length;c>1e4&&(t.State.calls=e(t.State.calls));for(var f=0;c>f;f++)if(t.State.calls[f]){var h=t.State.calls[f],i=h[0],j=h[2],n=h[3],o=!!n,q=null;n||(n=t.State.calls[f][3]=b-16);for(var r=Math.min((b-n)/j.duration,1),s=0,u=i.length;u>s;s++){var w=i[s],y=w.element;if(g(y)){var z=!1;if(j.display!==d&&null!==j.display&&"none"!==j.display){if("flex"===j.display){var A=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];m.each(A,function(a,b){v.setPropertyValue(y,"display",b)})}v.setPropertyValue(y,"display",j.display)}j.visibility!==d&&"hidden"!==j.visibility&&v.setPropertyValue(y,"visibility",j.visibility);for(var B in w)if("element"!==B){var C,D=w[B],E=p.isString(D.easing)?t.Easings[D.easing]:D.easing;if(1===r)C=D.endValue;else{var F=D.endValue-D.startValue;if(C=D.startValue+F*E(r,j,F),!o&&C===D.currentValue)continue}if(D.currentValue=C,"tween"===B)q=C;else{if(v.Hooks.registered[B]){var G=v.Hooks.getRoot(B),H=g(y).rootPropertyValueCache[G];H&&(D.rootPropertyValue=H)}var I=v.setPropertyValue(y,B,D.currentValue+(0===parseFloat(C)?"":D.unitType),D.rootPropertyValue,D.scrollData);v.Hooks.registered[B]&&(g(y).rootPropertyValueCache[G]=v.Normalizations.registered[G]?v.Normalizations.registered[G]("extract",null,I[1]):I[1]),"transform"===I[0]&&(z=!0)}}j.mobileHA&&g(y).transformCache.translate3d===d&&(g(y).transformCache.translate3d="(0px, 0px, 0px)",z=!0),z&&v.flushTransformCache(y)}}j.display!==d&&"none"!==j.display&&(t.State.calls[f][2].display=!1),j.visibility!==d&&"hidden"!==j.visibility&&(t.State.calls[f][2].visibility=!1),j.progress&&j.progress.call(h[1],h[1],r,Math.max(0,n+j.duration-b),n,q),1===r&&l(f)}}t.State.isTicking&&x(k)}function l(a,b){if(!t.State.calls[a])return!1;for(var c=t.State.calls[a][0],e=t.State.calls[a][1],f=t.State.calls[a][2],h=t.State.calls[a][4],i=!1,j=0,k=c.length;k>j;j++){var l=c[j].element;if(b||f.loop||("none"===f.display&&v.setPropertyValue(l,"display",f.display),"hidden"===f.visibility&&v.setPropertyValue(l,"visibility",f.visibility)),f.loop!==!0&&(m.queue(l)[1]===d||!/\.velocityQueueEntryFlag/i.test(m.queue(l)[1]))&&g(l)){g(l).isAnimating=!1,g(l).rootPropertyValueCache={};var n=!1;m.each(v.Lists.transforms3D,function(a,b){var c=/^scale/.test(b)?1:0,e=g(l).transformCache[b];g(l).transformCache[b]!==d&&new RegExp("^\\("+c+"[^.]").test(e)&&(n=!0,delete g(l).transformCache[b])}),f.mobileHA&&(n=!0,delete g(l).transformCache.translate3d),n&&v.flushTransformCache(l),v.Values.removeClass(l,"velocity-animating")}if(!b&&f.complete&&!f.loop&&j===k-1)try{f.complete.call(e,e)}catch(o){setTimeout(function(){throw o},1)}h&&f.loop!==!0&&h(e),g(l)&&f.loop===!0&&!b&&(m.each(g(l).tweensContainer,function(a,b){/^rotate/.test(a)&&360===parseFloat(b.endValue)&&(b.endValue=0,b.startValue=360),/^backgroundPosition/.test(a)&&100===parseFloat(b.endValue)&&"%"===b.unitType&&(b.endValue=0,b.startValue=100)}),t(l,"reverse",{loop:!0,delay:f.delay})),f.queue!==!1&&m.dequeue(l,f.queue)}t.State.calls[a]=!1;for(var p=0,q=t.State.calls.length;q>p;p++)if(t.State.calls[p]!==!1){i=!0;break}i===!1&&(t.State.isTicking=!1,delete t.State.calls,t.State.calls=[])}var m,n=function(){if(c.documentMode)return c.documentMode;for(var a=7;a>4;a--){var b=c.createElement("div");if(b.innerHTML="<!--[if IE "+a+"]><span></span><![endif]-->",b.getElementsByTagName("span").length)return b=null,a}return d}(),o=function(){var a=0;return b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame||function(b){var c,d=(new Date).getTime();return c=Math.max(0,16-(d-a)),a=d+c,setTimeout(function(){b(d+c)},c)}}(),p={isString:function(a){return"string"==typeof a},isArray:Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)},isFunction:function(a){return"[object Function]"===Object.prototype.toString.call(a)},isNode:function(a){return a&&a.nodeType},isNodeList:function(a){return"object"==typeof a&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(a))&&a.length!==d&&(0===a.length||"object"==typeof a[0]&&a[0].nodeType>0)},isWrapped:function(a){return a&&(a.jquery||b.Zepto&&b.Zepto.zepto.isZ(a))},isSVG:function(a){return b.SVGElement&&a instanceof b.SVGElement},isEmptyObject:function(a){for(var b in a)return!1;return!0}},q=!1;if(a.fn&&a.fn.jquery?(m=a,q=!0):m=b.Velocity.Utilities,8>=n&&!q)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=n)return void(jQuery.fn.velocity=jQuery.fn.animate);var r=400,s="swing",t={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:b.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:c.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:m,Redirects:{},Easings:{},Promise:b.Promise,defaults:{queue:"",duration:r,easing:s,begin:d,complete:d,progress:d,display:d,visibility:d,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(a){m.data(a,"velocity",{isSVG:p.isSVG(a),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:2},debug:!1};b.pageYOffset!==d?(t.State.scrollAnchor=b,t.State.scrollPropertyLeft="pageXOffset",t.State.scrollPropertyTop="pageYOffset"):(t.State.scrollAnchor=c.documentElement||c.body.parentNode||c.body,t.State.scrollPropertyLeft="scrollLeft",t.State.scrollPropertyTop="scrollTop");var u=function(){function a(a){return-a.tension*a.x-a.friction*a.v}function b(b,c,d){var e={x:b.x+d.dx*c,v:b.v+d.dv*c,tension:b.tension,friction:b.friction};return{dx:e.v,dv:a(e)}}function c(c,d){var e={dx:c.v,dv:a(c)},f=b(c,.5*d,e),g=b(c,.5*d,f),h=b(c,d,g),i=1/6*(e.dx+2*(f.dx+g.dx)+h.dx),j=1/6*(e.dv+2*(f.dv+g.dv)+h.dv);return c.x=c.x+i*d,c.v=c.v+j*d,c}return function d(a,b,e){var f,g,h,i={x:-1,v:0,tension:null,friction:null},j=[0],k=0,l=1e-4,m=.016;for(a=parseFloat(a)||500,b=parseFloat(b)||20,e=e||null,i.tension=a,i.friction=b,f=null!==e,f?(k=d(a,b),g=k/e*m):g=m;h=c(h||i,g),j.push(1+h.x),k+=16,Math.abs(h.x)>l&&Math.abs(h.v)>l;);return f?function(a){return j[a*(j.length-1)|0]}:k}}();t.Easings={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},spring:function(a){return 1-Math.cos(4.5*a*Math.PI)*Math.exp(6*-a)}},m.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(a,b){t.Easings[b[0]]=i.apply(null,b[1])});var v=t.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var a=0;a<v.Lists.colors.length;a++){var b="color"===v.Lists.colors[a]?"0 0 0 1":"255 255 255 1";v.Hooks.templates[v.Lists.colors[a]]=["Red Green Blue Alpha",b]}var c,d,e;if(n)for(c in v.Hooks.templates){d=v.Hooks.templates[c],e=d[0].split(" ");var f=d[1].match(v.RegEx.valueSplit);"Color"===e[0]&&(e.push(e.shift()),f.push(f.shift()),v.Hooks.templates[c]=[e.join(" "),f.join(" ")])}for(c in v.Hooks.templates){d=v.Hooks.templates[c],e=d[0].split(" ");for(var a in e){var g=c+e[a],h=a;v.Hooks.registered[g]=[c,h]}}},getRoot:function(a){var b=v.Hooks.registered[a];return b?b[0]:a},cleanRootPropertyValue:function(a,b){return v.RegEx.valueUnwrap.test(b)&&(b=b.match(v.RegEx.valueUnwrap)[1]),v.Values.isCSSNullValue(b)&&(b=v.Hooks.templates[a][1]),b},extractValue:function(a,b){var c=v.Hooks.registered[a];if(c){var d=c[0],e=c[1];return b=v.Hooks.cleanRootPropertyValue(d,b),b.toString().match(v.RegEx.valueSplit)[e]}return b},injectValue:function(a,b,c){var d=v.Hooks.registered[a];if(d){var e,f,g=d[0],h=d[1];return c=v.Hooks.cleanRootPropertyValue(g,c),e=c.toString().match(v.RegEx.valueSplit),e[h]=b,f=e.join(" ")}return c}},Normalizations:{registered:{clip:function(a,b,c){switch(a){case"name":return"clip";case"extract":var d;return v.RegEx.wrappedValueAlreadyExtracted.test(c)?d=c:(d=c.toString().match(v.RegEx.valueUnwrap),d=d?d[1].replace(/,(\s+)?/g," "):c),d;case"inject":return"rect("+c+")"}},blur:function(a,b,c){switch(a){case"name":return t.State.isFirefox?"filter":"-webkit-filter";case"extract":var d=parseFloat(c);if(!d&&0!==d){var e=c.toString().match(/blur\(([0-9]+[A-z]+)\)/i);d=e?e[1]:0}return d;case"inject":return parseFloat(c)?"blur("+c+")":"none"}},opacity:function(a,b,c){if(8>=n)switch(a){case"name":return"filter";case"extract":var d=c.toString().match(/alpha\(opacity=(.*)\)/i);return c=d?d[1]/100:1;case"inject":return b.style.zoom=1,parseFloat(c)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(c),10)+")"}else switch(a){case"name":return"opacity";case"extract":return c;case"inject":return c}}},register:function(){9>=n||t.State.isGingerbread||(v.Lists.transformsBase=v.Lists.transformsBase.concat(v.Lists.transforms3D));for(var a=0;a<v.Lists.transformsBase.length;a++)!function(){var b=v.Lists.transformsBase[a];v.Normalizations.registered[b]=function(a,c,e){switch(a){case"name":return"transform";case"extract":return g(c)===d||g(c).transformCache[b]===d?/^scale/i.test(b)?1:0:g(c).transformCache[b].replace(/[()]/g,"");case"inject":var f=!1;switch(b.substr(0,b.length-1)){case"translate":f=!/(%|px|em|rem|vw|vh|\d)$/i.test(e);break;case"scal":case"scale":t.State.isAndroid&&g(c).transformCache[b]===d&&1>e&&(e=1),f=!/(\d)$/i.test(e);break;case"skew":f=!/(deg|\d)$/i.test(e);break;case"rotate":f=!/(deg|\d)$/i.test(e)}return f||(g(c).transformCache[b]="("+e+")"),g(c).transformCache[b]}}}();for(var a=0;a<v.Lists.colors.length;a++)!function(){var b=v.Lists.colors[a];v.Normalizations.registered[b]=function(a,c,e){switch(a){case"name":return b;case"extract":var f;if(v.RegEx.wrappedValueAlreadyExtracted.test(e))f=e;else{var g,h={black:"rgb(0, 0, 0)",blue:"rgb(0, 0, 255)",gray:"rgb(128, 128, 128)",green:"rgb(0, 128, 0)",red:"rgb(255, 0, 0)",white:"rgb(255, 255, 255)"};/^[A-z]+$/i.test(e)?g=h[e]!==d?h[e]:h.black:v.RegEx.isHex.test(e)?g="rgb("+v.Values.hexToRgb(e).join(" ")+")":/^rgba?\(/i.test(e)||(g=h.black),f=(g||e).toString().match(v.RegEx.valueUnwrap)[1].replace(/,(\s+)?/g," ")}return 8>=n||3!==f.split(" ").length||(f+=" 1"),f;case"inject":return 8>=n?4===e.split(" ").length&&(e=e.split(/\s+/).slice(0,3).join(" ")):3===e.split(" ").length&&(e+=" 1"),(8>=n?"rgb":"rgba")+"("+e.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(a){return a.replace(/-(\w)/g,function(a,b){return b.toUpperCase()})},SVGAttribute:function(a){var b="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(n||t.State.isAndroid&&!t.State.isChrome)&&(b+="|transform"),new RegExp("^("+b+")$","i").test(a)},prefixCheck:function(a){if(t.State.prefixMatches[a])return[t.State.prefixMatches[a],!0];for(var b=["","Webkit","Moz","ms","O"],c=0,d=b.length;d>c;c++){var e;if(e=0===c?a:b[c]+a.replace(/^\w/,function(a){return a.toUpperCase()}),p.isString(t.State.prefixElement.style[e]))return t.State.prefixMatches[a]=e,[e,!0]}return[a,!1]}},Values:{hexToRgb:function(a){var b,c=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,d=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;return a=a.replace(c,function(a,b,c,d){return b+b+c+c+d+d}),b=d.exec(a),b?[parseInt(b[1],16),parseInt(b[2],16),parseInt(b[3],16)]:[0,0,0]},isCSSNullValue:function(a){return 0==a||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(a)},getUnitType:function(a){return/^(rotate|skew)/i.test(a)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(a)?"":"px"},getDisplayType:function(a){var b=a&&a.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(b)?"inline":/^(li)$/i.test(b)?"list-item":/^(tr)$/i.test(b)?"table-row":/^(table)$/i.test(b)?"table":/^(tbody)$/i.test(b)?"table-row-group":"block"},addClass:function(a,b){a.classList?a.classList.add(b):a.className+=(a.className.length?" ":"")+b},removeClass:function(a,b){a.classList?a.classList.remove(b):a.className=a.className.toString().replace(new RegExp("(^|\\s)"+b.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(a,c,e,f){function h(a,c){function e(){j&&v.setPropertyValue(a,"display","none")}var i=0;if(8>=n)i=m.css(a,c);else{var j=!1;if(/^(width|height)$/.test(c)&&0===v.getPropertyValue(a,"display")&&(j=!0,v.setPropertyValue(a,"display",v.Values.getDisplayType(a))),!f){if("height"===c&&"border-box"!==v.getPropertyValue(a,"boxSizing").toString().toLowerCase()){var k=a.offsetHeight-(parseFloat(v.getPropertyValue(a,"borderTopWidth"))||0)-(parseFloat(v.getPropertyValue(a,"borderBottomWidth"))||0)-(parseFloat(v.getPropertyValue(a,"paddingTop"))||0)-(parseFloat(v.getPropertyValue(a,"paddingBottom"))||0);return e(),k}if("width"===c&&"border-box"!==v.getPropertyValue(a,"boxSizing").toString().toLowerCase()){var l=a.offsetWidth-(parseFloat(v.getPropertyValue(a,"borderLeftWidth"))||0)-(parseFloat(v.getPropertyValue(a,"borderRightWidth"))||0)-(parseFloat(v.getPropertyValue(a,"paddingLeft"))||0)-(parseFloat(v.getPropertyValue(a,"paddingRight"))||0);return e(),l}}var o;o=g(a)===d?b.getComputedStyle(a,null):g(a).computedStyle?g(a).computedStyle:g(a).computedStyle=b.getComputedStyle(a,null),"borderColor"===c&&(c="borderTopColor"),i=9===n&&"filter"===c?o.getPropertyValue(c):o[c],(""===i||null===i)&&(i=a.style[c]),e()}if("auto"===i&&/^(top|right|bottom|left)$/i.test(c)){var p=h(a,"position");("fixed"===p||"absolute"===p&&/top|left/i.test(c))&&(i=m(a).position()[c]+"px")}return i}var i;if(v.Hooks.registered[c]){var j=c,k=v.Hooks.getRoot(j);e===d&&(e=v.getPropertyValue(a,v.Names.prefixCheck(k)[0])),v.Normalizations.registered[k]&&(e=v.Normalizations.registered[k]("extract",a,e)),i=v.Hooks.extractValue(j,e)}else if(v.Normalizations.registered[c]){var l,o;l=v.Normalizations.registered[c]("name",a),"transform"!==l&&(o=h(a,v.Names.prefixCheck(l)[0]),v.Values.isCSSNullValue(o)&&v.Hooks.templates[c]&&(o=v.Hooks.templates[c][1])),i=v.Normalizations.registered[c]("extract",a,o)}if(!/^[\d-]/.test(i))if(g(a)&&g(a).isSVG&&v.Names.SVGAttribute(c))if(/^(height|width)$/i.test(c))try{i=a.getBBox()[c]}catch(p){i=0}else i=a.getAttribute(c);else i=h(a,v.Names.prefixCheck(c)[0]);return v.Values.isCSSNullValue(i)&&(i=0),t.debug>=2&&console.log("Get "+c+": "+i),i},setPropertyValue:function(a,c,d,e,f){var h=c;if("scroll"===c)f.container?f.container["scroll"+f.direction]=d:"Left"===f.direction?b.scrollTo(d,f.alternateValue):b.scrollTo(f.alternateValue,d);else if(v.Normalizations.registered[c]&&"transform"===v.Normalizations.registered[c]("name",a))v.Normalizations.registered[c]("inject",a,d),h="transform",d=g(a).transformCache[c];else{if(v.Hooks.registered[c]){var i=c,j=v.Hooks.getRoot(c);e=e||v.getPropertyValue(a,j),d=v.Hooks.injectValue(i,d,e),c=j}if(v.Normalizations.registered[c]&&(d=v.Normalizations.registered[c]("inject",a,d),c=v.Normalizations.registered[c]("name",a)),h=v.Names.prefixCheck(c)[0],8>=n)try{a.style[h]=d}catch(k){t.debug&&console.log("Browser does not support ["+d+"] for ["+h+"]")}else g(a)&&g(a).isSVG&&v.Names.SVGAttribute(c)?a.setAttribute(c,d):a.style[h]=d;t.debug>=2&&console.log("Set "+c+" ("+h+"): "+d)}return[h,d]},flushTransformCache:function(a){function b(b){return parseFloat(v.getPropertyValue(a,b))}var c="";if((n||t.State.isAndroid&&!t.State.isChrome)&&g(a).isSVG){var d={translate:[b("translateX"),b("translateY")],skewX:[b("skewX")],skewY:[b("skewY")],scale:1!==b("scale")?[b("scale"),b("scale")]:[b("scaleX"),b("scaleY")],rotate:[b("rotateZ"),0,0]};m.each(g(a).transformCache,function(a){/^translate/i.test(a)?a="translate":/^scale/i.test(a)?a="scale":/^rotate/i.test(a)&&(a="rotate"),d[a]&&(c+=a+"("+d[a].join(" ")+") ",delete d[a])})}else{var e,f;m.each(g(a).transformCache,function(b){return e=g(a).transformCache[b],"transformPerspective"===b?(f=e,!0):(9===n&&"rotateZ"===b&&(b="rotate"),void(c+=b+e+" "))}),f&&(c="perspective"+f+" "+c)}v.setPropertyValue(a,"transform",c)}};v.Hooks.register(),v.Normalizations.register(),t.hook=function(a,b,c){var e=d;return a=f(a),m.each(a,function(a,f){if(g(f)===d&&t.init(f),c===d)e===d&&(e=t.CSS.getPropertyValue(f,b));else{var h=t.CSS.setPropertyValue(f,b,c);"transform"===h[0]&&t.CSS.flushTransformCache(f),e=h}}),e};var w=function(){function a(){return h?B.promise||null:i}function e(){function a(a){function l(a,b){var c=d,e=d,g=d;return p.isArray(a)?(c=a[0],!p.isArray(a[1])&&/^[\d-]/.test(a[1])||p.isFunction(a[1])||v.RegEx.isHex.test(a[1])?g=a[1]:(p.isString(a[1])&&!v.RegEx.isHex.test(a[1])||p.isArray(a[1]))&&(e=b?a[1]:j(a[1],h.duration),a[2]!==d&&(g=a[2]))):c=a,b||(e=e||h.easing),p.isFunction(c)&&(c=c.call(f,y,x)),p.isFunction(g)&&(g=g.call(f,y,x)),[c||0,e,g]}function n(a,b){var c,d;return d=(b||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(a){return c=a,""}),c||(c=v.Values.getUnitType(a)),[d,c]}function r(){var a={myParent:f.parentNode||c.body,position:v.getPropertyValue(f,"position"),fontSize:v.getPropertyValue(f,"fontSize")},d=a.position===I.lastPosition&&a.myParent===I.lastParent,e=a.fontSize===I.lastFontSize;I.lastParent=a.myParent,I.lastPosition=a.position,I.lastFontSize=a.fontSize;var h=100,i={};if(e&&d)i.emToPx=I.lastEmToPx,i.percentToPxWidth=I.lastPercentToPxWidth,i.percentToPxHeight=I.lastPercentToPxHeight;else{var j=g(f).isSVG?c.createElementNS("http://www.w3.org/2000/svg","rect"):c.createElement("div");t.init(j),a.myParent.appendChild(j),m.each(["overflow","overflowX","overflowY"],function(a,b){t.CSS.setPropertyValue(j,b,"hidden")}),t.CSS.setPropertyValue(j,"position",a.position),t.CSS.setPropertyValue(j,"fontSize",a.fontSize),t.CSS.setPropertyValue(j,"boxSizing","content-box"),m.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(a,b){t.CSS.setPropertyValue(j,b,h+"%")}),t.CSS.setPropertyValue(j,"paddingLeft",h+"em"),i.percentToPxWidth=I.lastPercentToPxWidth=(parseFloat(v.getPropertyValue(j,"width",null,!0))||1)/h,i.percentToPxHeight=I.lastPercentToPxHeight=(parseFloat(v.getPropertyValue(j,"height",null,!0))||1)/h,i.emToPx=I.lastEmToPx=(parseFloat(v.getPropertyValue(j,"paddingLeft"))||1)/h,a.myParent.removeChild(j)}return null===I.remToPx&&(I.remToPx=parseFloat(v.getPropertyValue(c.body,"fontSize"))||16),null===I.vwToPx&&(I.vwToPx=parseFloat(b.innerWidth)/100,I.vhToPx=parseFloat(b.innerHeight)/100),i.remToPx=I.remToPx,i.vwToPx=I.vwToPx,i.vhToPx=I.vhToPx,t.debug>=1&&console.log("Unit ratios: "+JSON.stringify(i),f),i}if(h.begin&&0===y)try{h.begin.call(o,o)}catch(u){setTimeout(function(){throw u},1)}if("scroll"===C){var w,z,A,D=/^x$/i.test(h.axis)?"Left":"Top",E=parseFloat(h.offset)||0;h.container?p.isWrapped(h.container)||p.isNode(h.container)?(h.container=h.container[0]||h.container,w=h.container["scroll"+D],A=w+m(f).position()[D.toLowerCase()]+E):h.container=null:(w=t.State.scrollAnchor[t.State["scrollProperty"+D]],z=t.State.scrollAnchor[t.State["scrollProperty"+("Left"===D?"Top":"Left")]],A=m(f).offset()[D.toLowerCase()]+E),i={scroll:{rootPropertyValue:!1,startValue:w,currentValue:w,endValue:A,unitType:"",easing:h.easing,scrollData:{container:h.container,direction:D,alternateValue:z}},element:f},t.debug&&console.log("tweensContainer (scroll): ",i.scroll,f)}else if("reverse"===C){if(!g(f).tweensContainer)return void m.dequeue(f,h.queue);"none"===g(f).opts.display&&(g(f).opts.display="auto"),"hidden"===g(f).opts.visibility&&(g(f).opts.visibility="visible"),g(f).opts.loop=!1,g(f).opts.begin=null,g(f).opts.complete=null,s.easing||delete h.easing,s.duration||delete h.duration,h=m.extend({},g(f).opts,h);var F=m.extend(!0,{},g(f).tweensContainer);for(var G in F)if("element"!==G){var H=F[G].startValue;F[G].startValue=F[G].currentValue=F[G].endValue,F[G].endValue=H,p.isEmptyObject(s)||(F[G].easing=h.easing),t.debug&&console.log("reverse tweensContainer ("+G+"): "+JSON.stringify(F[G]),f)}i=F}else if("start"===C){var F;g(f).tweensContainer&&g(f).isAnimating===!0&&(F=g(f).tweensContainer),m.each(q,function(a,b){if(RegExp("^"+v.Lists.colors.join("$|^")+"$").test(a)){var c=l(b,!0),e=c[0],f=c[1],g=c[2];if(v.RegEx.isHex.test(e)){for(var h=["Red","Green","Blue"],i=v.Values.hexToRgb(e),j=g?v.Values.hexToRgb(g):d,k=0;k<h.length;k++){var m=[i[k]];f&&m.push(f),j!==d&&m.push(j[k]),q[a+h[k]]=m}delete q[a]}}});for(var K in q){var L=l(q[K]),M=L[0],N=L[1],O=L[2];K=v.Names.camelCase(K);var P=v.Hooks.getRoot(K),Q=!1;if(g(f).isSVG||"tween"===P||v.Names.prefixCheck(P)[1]!==!1||v.Normalizations.registered[P]!==d){(h.display!==d&&null!==h.display&&"none"!==h.display||h.visibility!==d&&"hidden"!==h.visibility)&&/opacity|filter/.test(K)&&!O&&0!==M&&(O=0),h._cacheValues&&F&&F[K]?(O===d&&(O=F[K].endValue+F[K].unitType),Q=g(f).rootPropertyValueCache[P]):v.Hooks.registered[K]?O===d?(Q=v.getPropertyValue(f,P),O=v.getPropertyValue(f,K,Q)):Q=v.Hooks.templates[P][1]:O===d&&(O=v.getPropertyValue(f,K));var R,S,T,U=!1;if(R=n(K,O),O=R[0],T=R[1],R=n(K,M),M=R[0].replace(/^([+-\/*])=/,function(a,b){return U=b,""}),S=R[1],O=parseFloat(O)||0,M=parseFloat(M)||0,"%"===S&&(/^(fontSize|lineHeight)$/.test(K)?(M/=100,S="em"):/^scale/.test(K)?(M/=100,S=""):/(Red|Green|Blue)$/i.test(K)&&(M=M/100*255,S="")),/[\/*]/.test(U))S=T;else if(T!==S&&0!==O)if(0===M)S=T;else{e=e||r();var V=/margin|padding|left|right|width|text|word|letter/i.test(K)||/X$/.test(K)||"x"===K?"x":"y";
-switch(T){case"%":O*="x"===V?e.percentToPxWidth:e.percentToPxHeight;break;case"px":break;default:O*=e[T+"ToPx"]}switch(S){case"%":O*=1/("x"===V?e.percentToPxWidth:e.percentToPxHeight);break;case"px":break;default:O*=1/e[S+"ToPx"]}}switch(U){case"+":M=O+M;break;case"-":M=O-M;break;case"*":M=O*M;break;case"/":M=O/M}i[K]={rootPropertyValue:Q,startValue:O,currentValue:O,endValue:M,unitType:S,easing:N},t.debug&&console.log("tweensContainer ("+K+"): "+JSON.stringify(i[K]),f)}else t.debug&&console.log("Skipping ["+P+"] due to a lack of browser support.")}i.element=f}i.element&&(v.Values.addClass(f,"velocity-animating"),J.push(i),""===h.queue&&(g(f).tweensContainer=i,g(f).opts=h),g(f).isAnimating=!0,y===x-1?(t.State.calls.push([J,o,h,null,B.resolver]),t.State.isTicking===!1&&(t.State.isTicking=!0,k())):y++)}var e,f=this,h=m.extend({},t.defaults,s),i={};switch(g(f)===d&&t.init(f),parseFloat(h.delay)&&h.queue!==!1&&m.queue(f,h.queue,function(a){t.velocityQueueEntryFlag=!0,g(f).delayTimer={setTimeout:setTimeout(a,parseFloat(h.delay)),next:a}}),h.duration.toString().toLowerCase()){case"fast":h.duration=200;break;case"normal":h.duration=r;break;case"slow":h.duration=600;break;default:h.duration=parseFloat(h.duration)||1}t.mock!==!1&&(t.mock===!0?h.duration=h.delay=1:(h.duration*=parseFloat(t.mock)||1,h.delay*=parseFloat(t.mock)||1)),h.easing=j(h.easing,h.duration),h.begin&&!p.isFunction(h.begin)&&(h.begin=null),h.progress&&!p.isFunction(h.progress)&&(h.progress=null),h.complete&&!p.isFunction(h.complete)&&(h.complete=null),h.display!==d&&null!==h.display&&(h.display=h.display.toString().toLowerCase(),"auto"===h.display&&(h.display=t.CSS.Values.getDisplayType(f))),h.visibility!==d&&null!==h.visibility&&(h.visibility=h.visibility.toString().toLowerCase()),h.mobileHA=h.mobileHA&&t.State.isMobile&&!t.State.isGingerbread,h.queue===!1?h.delay?setTimeout(a,h.delay):a():m.queue(f,h.queue,function(b,c){return c===!0?(B.promise&&B.resolver(o),!0):(t.velocityQueueEntryFlag=!0,void a(b))}),""!==h.queue&&"fx"!==h.queue||"inprogress"===m.queue(f)[0]||m.dequeue(f)}var h,i,n,o,q,s,u=arguments[0]&&(arguments[0].p||m.isPlainObject(arguments[0].properties)&&!arguments[0].properties.names||p.isString(arguments[0].properties));if(p.isWrapped(this)?(h=!1,n=0,o=this,i=this):(h=!0,n=1,o=u?arguments[0].elements||arguments[0].e:arguments[0]),o=f(o)){u?(q=arguments[0].properties||arguments[0].p,s=arguments[0].options||arguments[0].o):(q=arguments[n],s=arguments[n+1]);var x=o.length,y=0;if(!/^(stop|finish)$/i.test(q)&&!m.isPlainObject(s)){var z=n+1;s={};for(var A=z;A<arguments.length;A++)p.isArray(arguments[A])||!/^(fast|normal|slow)$/i.test(arguments[A])&&!/^\d/.test(arguments[A])?p.isString(arguments[A])||p.isArray(arguments[A])?s.easing=arguments[A]:p.isFunction(arguments[A])&&(s.complete=arguments[A]):s.duration=arguments[A]}var B={promise:null,resolver:null,rejecter:null};h&&t.Promise&&(B.promise=new t.Promise(function(a,b){B.resolver=a,B.rejecter=b}));var C;switch(q){case"scroll":C="scroll";break;case"reverse":C="reverse";break;case"finish":case"stop":m.each(o,function(a,b){g(b)&&g(b).delayTimer&&(clearTimeout(g(b).delayTimer.setTimeout),g(b).delayTimer.next&&g(b).delayTimer.next(),delete g(b).delayTimer)});var D=[];return m.each(t.State.calls,function(a,b){b&&m.each(b[1],function(c,e){var f=s===d?"":s;return f!==!0&&b[2].queue!==f&&(s!==d||b[2].queue!==!1)||void m.each(o,function(c,d){d===e&&((s===!0||p.isString(s))&&(m.each(m.queue(d,p.isString(s)?s:""),function(a,b){p.isFunction(b)&&b(null,!0)}),m.queue(d,p.isString(s)?s:"",[])),"stop"===q?(g(d)&&g(d).tweensContainer&&f!==!1&&m.each(g(d).tweensContainer,function(a,b){b.endValue=b.currentValue}),D.push(a)):"finish"===q&&(b[2].duration=1))})})}),"stop"===q&&(m.each(D,function(a,b){l(b,!0)}),B.promise&&B.resolver(o)),a();default:if(!m.isPlainObject(q)||p.isEmptyObject(q)){if(p.isString(q)&&t.Redirects[q]){var E=m.extend({},s),F=E.duration,G=E.delay||0;return E.backwards===!0&&(o=m.extend(!0,[],o).reverse()),m.each(o,function(a,b){parseFloat(E.stagger)?E.delay=G+parseFloat(E.stagger)*a:p.isFunction(E.stagger)&&(E.delay=G+E.stagger.call(b,a,x)),E.drag&&(E.duration=parseFloat(F)||(/^(callout|transition)/.test(q)?1e3:r),E.duration=Math.max(E.duration*(E.backwards?1-a/x:(a+1)/x),.75*E.duration,200)),t.Redirects[q].call(b,b,E||{},a,x,o,B.promise?B:d)}),a()}var H="Velocity: First argument ("+q+") was not a property map, a known action, or a registered redirect. Aborting.";return B.promise?B.rejecter(new Error(H)):console.log(H),a()}C="start"}var I={lastParent:null,lastPosition:null,lastFontSize:null,lastPercentToPxWidth:null,lastPercentToPxHeight:null,lastEmToPx:null,remToPx:null,vwToPx:null,vhToPx:null},J=[];m.each(o,function(a,b){p.isNode(b)&&e.call(b)});var K,E=m.extend({},t.defaults,s);if(E.loop=parseInt(E.loop),K=2*E.loop-1,E.loop)for(var L=0;K>L;L++){var M={delay:E.delay,progress:E.progress};L===K-1&&(M.display=E.display,M.visibility=E.visibility,M.complete=E.complete),w(o,"reverse",M)}return a()}};t=m.extend(w,t),t.animate=w;var x=b.requestAnimationFrame||o;return t.State.isMobile||c.hidden===d||c.addEventListener("visibilitychange",function(){c.hidden?(x=function(a){return setTimeout(function(){a(!0)},16)},k()):x=b.requestAnimationFrame||o}),a.Velocity=t,a!==b&&(a.fn.velocity=w,a.fn.velocity.defaults=t.defaults),m.each(["Down","Up"],function(a,b){t.Redirects["slide"+b]=function(a,c,e,f,g,h){var i=m.extend({},c),j=i.begin,k=i.complete,l={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},n={};i.display===d&&(i.display="Down"===b?"inline"===t.CSS.Values.getDisplayType(a)?"inline-block":"block":"none"),i.begin=function(){j&&j.call(g,g);for(var c in l){n[c]=a.style[c];var d=t.CSS.getPropertyValue(a,c);l[c]="Down"===b?[d,0]:[0,d]}n.overflow=a.style.overflow,a.style.overflow="hidden"},i.complete=function(){for(var b in n)a.style[b]=n[b];k&&k.call(g,g),h&&h.resolver(g)},t(a,l,i)}}),m.each(["In","Out"],function(a,b){t.Redirects["fade"+b]=function(a,c,e,f,g,h){var i=m.extend({},c),j={opacity:"In"===b?1:0},k=i.complete;i.complete=e!==f-1?i.begin=null:function(){k&&k.call(g,g),h&&h.resolver(g)},i.display===d&&(i.display="In"===b?"auto":"none"),t(this,j,i)}}),t}(window.jQuery||window.Zepto||window,window,document)})),!function(a,b,c,d){"use strict";function e(a,b,c){return setTimeout(k(a,c),b)}function f(a,b,c){return!!Array.isArray(a)&&(g(a,c[b],c),!0)}function g(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e<a.length;)b.call(c,a[e],e,a),e++;else for(e in a)a.hasOwnProperty(e)&&b.call(c,a[e],e,a)}function h(a,b,c){for(var e=Object.keys(b),f=0;f<e.length;)(!c||c&&a[e[f]]===d)&&(a[e[f]]=b[e[f]]),f++;return a}function i(a,b){return h(a,b,!0)}function j(a,b,c){var d,e=b.prototype;d=a.prototype=Object.create(e),d.constructor=a,d._super=e,c&&h(d,c)}function k(a,b){return function(){return a.apply(b,arguments)}}function l(a,b){return typeof a==ka?a.apply(b?b[0]||d:d,b):a}function m(a,b){return a===d?b:a}function n(a,b,c){g(r(b),function(b){a.addEventListener(b,c,!1)})}function o(a,b,c){g(r(b),function(b){a.removeEventListener(b,c,!1)})}function p(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function q(a,b){return a.indexOf(b)>-1}function r(a){return a.trim().split(/\s+/g)}function s(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;d<a.length;){if(c&&a[d][c]==b||!c&&a[d]===b)return d;d++}return-1}function t(a){return Array.prototype.slice.call(a,0)}function u(a,b,c){for(var d=[],e=[],f=0;f<a.length;){var g=b?a[f][b]:a[f];s(e,g)<0&&d.push(a[f]),e[f]=g,f++}return c&&(d=b?d.sort(function(a,c){return a[b]>c[b]}):d.sort()),d}function v(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g<ia.length;){if(c=ia[g],e=c?c+f:b,e in a)return e;g++}return d}function w(){return oa++}function x(a){var b=a.ownerDocument;return b.defaultView||b.parentWindow}function y(a,b){var c=this;this.manager=a,this.callback=b,this.element=a.element,this.target=a.options.inputTarget,this.domHandler=function(b){l(a.options.enable,[a])&&c.handler(b)},this.init()}function z(a){var b,c=a.options.inputClass;return new(b=c?c:ra?N:sa?Q:qa?S:M)(a,A)}function A(a,b,c){var d=c.pointers.length,e=c.changedPointers.length,f=b&ya&&0===d-e,g=b&(Aa|Ba)&&0===d-e;c.isFirst=!!f,c.isFinal=!!g,f&&(a.session={}),c.eventType=b,B(a,c),a.emit("hammer.input",c),a.recognize(c),a.session.prevInput=c}function B(a,b){var c=a.session,d=b.pointers,e=d.length;c.firstInput||(c.firstInput=E(b)),e>1&&!c.firstMultiple?c.firstMultiple=E(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=F(d);b.timeStamp=na(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=J(h,i),b.distance=I(h,i),C(c,b),b.offsetDirection=H(b.deltaX,b.deltaY),b.scale=g?L(g.pointers,d):1,b.rotation=g?K(g.pointers,d):0,D(c,b);var j=a.element;p(b.srcEvent.target,j)&&(j=b.srcEvent.target),b.target=j}function C(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};(b.eventType===ya||f.eventType===Aa)&&(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function D(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ba&&(i>xa||h.velocity===d)){var j=h.deltaX-b.deltaX,k=h.deltaY-b.deltaY,l=G(i,j,k);e=l.x,f=l.y,c=ma(l.x)>ma(l.y)?l.x:l.y,g=H(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function E(a){for(var b=[],c=0;c<a.pointers.length;)b[c]={clientX:la(a.pointers[c].clientX),clientY:la(a.pointers[c].clientY)},c++;return{timeStamp:na(),pointers:b,center:F(b),deltaX:a.deltaX,deltaY:a.deltaY}}function F(a){var b=a.length;if(1===b)return{x:la(a[0].clientX),y:la(a[0].clientY)};for(var c=0,d=0,e=0;b>e;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:la(c/b),y:la(d/b)}}function G(a,b,c){return{x:b/a||0,y:c/a||0}}function H(a,b){return a===b?Ca:ma(a)>=ma(b)?a>0?Da:Ea:b>0?Fa:Ga}function I(a,b,c){c||(c=Ka);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function J(a,b,c){c||(c=Ka);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function K(a,b){return J(b[1],b[0],La)-J(a[1],a[0],La)}function L(a,b){return I(b[0],b[1],La)/I(a[0],a[1],La)}function M(){this.evEl=Na,this.evWin=Oa,this.allow=!0,this.pressed=!1,y.apply(this,arguments)}function N(){this.evEl=Ra,this.evWin=Sa,y.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function O(){this.evTarget=Ua,this.evWin=Va,this.started=!1,y.apply(this,arguments)}function P(a,b){var c=t(a.touches),d=t(a.changedTouches);return b&(Aa|Ba)&&(c=u(c.concat(d),"identifier",!0)),[c,d]}function Q(){this.evTarget=Xa,this.targetIds={},y.apply(this,arguments)}function R(a,b){var c=t(a.touches),d=this.targetIds;if(b&(ya|za)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=t(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return p(a.target,i)}),b===ya)for(e=0;e<f.length;)d[f[e].identifier]=!0,e++;for(e=0;e<g.length;)d[g[e].identifier]&&h.push(g[e]),b&(Aa|Ba)&&delete d[g[e].identifier],e++;return h.length?[u(f.concat(h),"identifier",!0),h]:void 0}function S(){y.apply(this,arguments);var a=k(this.handler,this);this.touch=new Q(this.manager,a),this.mouse=new M(this.manager,a)}function T(a,b){this.manager=a,this.set(b)}function U(a){if(q(a,bb))return bb;var b=q(a,cb),c=q(a,db);return b&&c?cb+" "+db:b||c?b?cb:db:q(a,ab)?ab:_a}function V(a){this.id=w(),this.manager=null,this.options=i(a||{},this.defaults),this.options.enable=m(this.options.enable,!0),this.state=eb,this.simultaneous={},this.requireFail=[]}function W(a){return a&jb?"cancel":a&hb?"end":a&gb?"move":a&fb?"start":""}function X(a){return a==Ga?"down":a==Fa?"up":a==Da?"left":a==Ea?"right":""}function Y(a,b){var c=b.manager;return c?c.get(a):a}function Z(){V.apply(this,arguments)}function $(){Z.apply(this,arguments),this.pX=null,this.pY=null}function _(){Z.apply(this,arguments)}function aa(){V.apply(this,arguments),this._timer=null,this._input=null}function ba(){Z.apply(this,arguments)}function ca(){Z.apply(this,arguments)}function da(){V.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function ea(a,b){return b=b||{},b.recognizers=m(b.recognizers,ea.defaults.preset),new fa(a,b)}function fa(a,b){b=b||{},this.options=i(b,ea.defaults),this.options.inputTarget=this.options.inputTarget||a,this.handlers={},this.session={},this.recognizers=[],this.element=a,this.input=z(this),this.touchAction=new T(this,this.options.touchAction),ga(this,!0),g(b.recognizers,function(a){var b=this.add(new a[0](a[1]));a[2]&&b.recognizeWith(a[2]),a[3]&&b.requireFailure(a[3])},this)}function ga(a,b){var c=a.element;g(a.options.cssProps,function(a,d){c.style[v(c.style,d)]=b?a:""})}function ha(a,c){var d=b.createEvent("Event");d.initEvent(a,!0,!0),d.gesture=c,c.target.dispatchEvent(d)}var ia=["","webkit","moz","MS","ms","o"],ja=b.createElement("div"),ka="function",la=Math.round,ma=Math.abs,na=Date.now,oa=1,pa=/mobile|tablet|ip(ad|hone|od)|android/i,qa="ontouchstart"in a,ra=v(a,"PointerEvent")!==d,sa=qa&&pa.test(navigator.userAgent),ta="touch",ua="pen",va="mouse",wa="kinect",xa=25,ya=1,za=2,Aa=4,Ba=8,Ca=1,Da=2,Ea=4,Fa=8,Ga=16,Ha=Da|Ea,Ia=Fa|Ga,Ja=Ha|Ia,Ka=["x","y"],La=["clientX","clientY"];y.prototype={handler:function(){},init:function(){this.evEl&&n(this.element,this.evEl,this.domHandler),this.evTarget&&n(this.target,this.evTarget,this.domHandler),this.evWin&&n(x(this.element),this.evWin,this.domHandler)},destroy:function(){this.evEl&&o(this.element,this.evEl,this.domHandler),this.evTarget&&o(this.target,this.evTarget,this.domHandler),this.evWin&&o(x(this.element),this.evWin,this.domHandler)}};var Ma={mousedown:ya,mousemove:za,mouseup:Aa},Na="mousedown",Oa="mousemove mouseup";j(M,y,{handler:function(a){var b=Ma[a.type];b&ya&&0===a.button&&(this.pressed=!0),b&za&&1!==a.which&&(b=Aa),this.pressed&&this.allow&&(b&Aa&&(this.pressed=!1),this.callback(this.manager,b,{pointers:[a],changedPointers:[a],pointerType:va,srcEvent:a}))}});var Pa={pointerdown:ya,pointermove:za,pointerup:Aa,pointercancel:Ba,pointerout:Ba},Qa={2:ta,3:ua,4:va,5:wa},Ra="pointerdown",Sa="pointermove pointerup pointercancel";a.MSPointerEvent&&(Ra="MSPointerDown",Sa="MSPointerMove MSPointerUp MSPointerCancel"),j(N,y,{handler:function(a){var b=this.store,c=!1,d=a.type.toLowerCase().replace("ms",""),e=Pa[d],f=Qa[a.pointerType]||a.pointerType,g=f==ta,h=s(b,a.pointerId,"pointerId");e&ya&&(0===a.button||g)?0>h&&(b.push(a),h=b.length-1):e&(Aa|Ba)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var Ta={touchstart:ya,touchmove:za,touchend:Aa,touchcancel:Ba},Ua="touchstart",Va="touchstart touchmove touchend touchcancel";j(O,y,{handler:function(a){var b=Ta[a.type];if(b===ya&&(this.started=!0),this.started){var c=P.call(this,a,b);b&(Aa|Ba)&&0===c[0].length-c[1].length&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:ta,srcEvent:a})}}});var Wa={touchstart:ya,touchmove:za,touchend:Aa,touchcancel:Ba},Xa="touchstart touchmove touchend touchcancel";j(Q,y,{handler:function(a){var b=Wa[a.type],c=R.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:ta,srcEvent:a})}}),j(S,y,{handler:function(a,b,c){var d=c.pointerType==ta,e=c.pointerType==va;if(d)this.mouse.allow=!1;else if(e&&!this.mouse.allow)return;b&(Aa|Ba)&&(this.mouse.allow=!0),this.callback(a,b,c)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var Ya=v(ja.style,"touchAction"),Za=Ya!==d,$a="compute",_a="auto",ab="manipulation",bb="none",cb="pan-x",db="pan-y";T.prototype={set:function(a){a==$a&&(a=this.compute()),Za&&(this.manager.element.style[Ya]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return g(this.manager.recognizers,function(b){l(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),U(a.join(" "))},preventDefaults:function(a){if(!Za){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return void b.preventDefault();var d=this.actions,e=q(d,bb),f=q(d,db),g=q(d,cb);return e||f&&c&Ha||g&&c&Ia?this.preventSrc(b):void 0}},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var eb=1,fb=2,gb=4,hb=8,ib=hb,jb=16,kb=32;V.prototype={defaults:{},set:function(a){return h(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(f(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=Y(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return f(a,"dropRecognizeWith",this)?this:(a=Y(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(f(a,"requireFailure",this))return this;var b=this.requireFail;return a=Y(a,this),-1===s(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(f(a,"dropRequireFailure",this))return this;a=Y(a,this);var b=s(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function b(b){c.manager.emit(c.options.event+(b?W(d):""),a)}var c=this,d=this.state;hb>d&&b(!0),b(),d>=hb&&b(!0)},tryEmit:function(a){return this.canEmit()?this.emit(a):void(this.state=kb)},canEmit:function(){for(var a=0;a<this.requireFail.length;){if(!(this.requireFail[a].state&(kb|eb)))return!1;a++}return!0},recognize:function(a){var b=h({},a);return l(this.options.enable,[this,b])?(this.state&(ib|jb|kb)&&(this.state=eb),this.state=this.process(b),void(this.state&(fb|gb|hb|jb)&&this.tryEmit(b))):(this.reset(),void(this.state=kb))},process:function(){},getTouchAction:function(){},reset:function(){}},j(Z,V,{defaults:{pointers:1},attrTest:function(a){var b=this.options.pointers;return 0===b||a.pointers.length===b},process:function(a){var b=this.state,c=a.eventType,d=b&(fb|gb),e=this.attrTest(a);return d&&(c&Ba||!e)?b|jb:d||e?c&Aa?b|hb:b&fb?b|gb:fb:kb}}),j($,Z,{defaults:{event:"pan",threshold:10,pointers:1,direction:Ja},getTouchAction:function(){var a=this.options.direction,b=[];return a&Ha&&b.push(db),a&Ia&&b.push(cb),b},directionTest:function(a){var b=this.options,c=!0,d=a.distance,e=a.direction,f=a.deltaX,g=a.deltaY;return e&b.direction||(b.direction&Ha?(e=0===f?Ca:0>f?Da:Ea,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?Ca:0>g?Fa:Ga,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return Z.prototype.attrTest.call(this,a)&&(this.state&fb||!(this.state&fb)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=X(a.direction);b&&this.manager.emit(this.options.event+b,a),this._super.emit.call(this,a)}}),j(_,Z,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[bb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&fb)},emit:function(a){if(this._super.emit.call(this,a),1!==a.scale){var b=a.scale<1?"in":"out";this.manager.emit(this.options.event+b,a)}}}),j(aa,V,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[_a]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaTime>b.time;if(this._input=a,!d||!c||a.eventType&(Aa|Ba)&&!f)this.reset();else if(a.eventType&ya)this.reset(),this._timer=e(function(){this.state=ib,this.tryEmit()},b.time,this);else if(a.eventType&Aa)return ib;return kb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===ib&&(a&&a.eventType&Aa?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=na(),this.manager.emit(this.options.event,this._input)))}}),j(ba,Z,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[bb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&fb)}}),j(ca,Z,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:Ha|Ia,pointers:1},getTouchAction:function(){return $.prototype.getTouchAction.call(this)},attrTest:function(a){var b,c=this.options.direction;return c&(Ha|Ia)?b=a.velocity:c&Ha?b=a.velocityX:c&Ia&&(b=a.velocityY),this._super.attrTest.call(this,a)&&c&a.direction&&a.distance>this.options.threshold&&ma(b)>this.options.velocity&&a.eventType&Aa},emit:function(a){var b=X(a.direction);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),j(da,V,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[ab]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaTime<b.time;if(this.reset(),a.eventType&ya&&0===this.count)return this.failTimeout();if(d&&f&&c){if(a.eventType!=Aa)return this.failTimeout();var g=!this.pTime||a.timeStamp-this.pTime<b.interval,h=!this.pCenter||I(this.pCenter,a.center)<b.posThreshold;this.pTime=a.timeStamp,this.pCenter=a.center,h&&g?this.count+=1:this.count=1,this._input=a;var i=this.count%b.taps;if(0===i)return this.hasRequireFailures()?(this._timer=e(function(){this.state=ib,this.tryEmit()},b.interval,this),fb):ib}return kb},failTimeout:function(){return this._timer=e(function(){this.state=kb},this.options.interval,this),kb},reset:function(){clearTimeout(this._timer)},emit:function(){this.state==ib&&(this._input.tapCount=this.count,this.manager.emit(this.options.event,this._input))}}),ea.VERSION="2.0.4",ea.defaults={domEvents:!1,touchAction:$a,enable:!0,inputTarget:null,inputClass:null,preset:[[ba,{enable:!1}],[_,{enable:!1},["rotate"]],[ca,{direction:Ha}],[$,{direction:Ha},["swipe"]],[da],[da,{event:"doubletap",taps:2},["tap"]],[aa]],cssProps:{userSelect:"default",touchSelect:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}};var lb=1,mb=2;fa.prototype={set:function(a){return h(this.options,a),a.touchAction&&this.touchAction.update(),a.inputTarget&&(this.input.destroy(),this.input.target=a.inputTarget,this.input.init()),this},stop:function(a){this.session.stopped=a?mb:lb},recognize:function(a){var b=this.session;if(!b.stopped){this.touchAction.preventDefaults(a);var c,d=this.recognizers,e=b.curRecognizer;(!e||e&&e.state&ib)&&(e=b.curRecognizer=null);for(var f=0;f<d.length;)c=d[f],b.stopped===mb||e&&c!=e&&!c.canRecognizeWith(e)?c.reset():c.recognize(a),!e&&c.state&(fb|gb|hb)&&(e=b.curRecognizer=c),f++}},get:function(a){if(a instanceof V)return a;for(var b=this.recognizers,c=0;c<b.length;c++)if(b[c].options.event==a)return b[c];return null},add:function(a){if(f(a,"add",this))return this;var b=this.get(a.options.event);return b&&this.remove(b),this.recognizers.push(a),a.manager=this,this.touchAction.update(),a},remove:function(a){if(f(a,"remove",this))return this;var b=this.recognizers;return a=this.get(a),b.splice(s(b,a),1),this.touchAction.update(),this},on:function(a,b){var c=this.handlers;return g(r(a),function(a){c[a]=c[a]||[],c[a].push(b)}),this},off:function(a,b){var c=this.handlers;return g(r(a),function(a){b?c[a].splice(s(c[a],b),1):delete c[a]}),this},emit:function(a,b){this.options.domEvents&&ha(a,b);var c=this.handlers[a]&&this.handlers[a].slice();if(c&&c.length){b.type=a,b.preventDefault=function(){b.srcEvent.preventDefault()};for(var d=0;d<c.length;)c[d](b),d++}},destroy:function(){this.element&&ga(this,!1),this.handlers={},this.session={},this.input.destroy(),this.element=null}},h(ea,{INPUT_START:ya,INPUT_MOVE:za,INPUT_END:Aa,INPUT_CANCEL:Ba,STATE_POSSIBLE:eb,STATE_BEGAN:fb,STATE_CHANGED:gb,STATE_ENDED:hb,STATE_RECOGNIZED:ib,STATE_CANCELLED:jb,STATE_FAILED:kb,DIRECTION_NONE:Ca,DIRECTION_LEFT:Da,DIRECTION_RIGHT:Ea,DIRECTION_UP:Fa,DIRECTION_DOWN:Ga,DIRECTION_HORIZONTAL:Ha,DIRECTION_VERTICAL:Ia,DIRECTION_ALL:Ja,Manager:fa,Input:y,TouchAction:T,TouchInput:Q,MouseInput:M,PointerEventInput:N,TouchMouseInput:S,SingleTouchInput:O,Recognizer:V,AttrRecognizer:Z,Tap:da,Pan:$,Swipe:ca,Pinch:_,Rotate:ba,Press:aa,on:n,off:o,each:g,merge:i,extend:h,inherit:j,bindFn:k,prefixed:v}),typeof define==ka&&define.amd?define(function(){return ea}):"undefined"!=typeof module&&module.exports?module.exports=ea:a[c]=ea}(window,document,"Hammer"),function(a){"function"==typeof define&&define.amd?define(["jquery","hammerjs"],a):"object"==typeof exports?a(require("jquery"),require("hammerjs")):a(jQuery,Hammer)}(function(a,b){function c(c,d){var e=a(c);e.data("hammer")||e.data("hammer",new b(e[0],d))}a.fn.hammer=function(a){return this.each(function(){c(this,a)})},b.Manager.prototype.emit=function(b){return function(c,d){b.call(this,c,d),a(this.element).trigger({type:c,gesture:d})}}(b.Manager.prototype.emit)}),function(a){a.Package?Materialize={}:a.Materialize={}}(window),function(a){for(var b=0,c=["webkit","moz"],d=a.requestAnimationFrame,e=a.cancelAnimationFrame,f=c.length;--f>=0&&!d;)d=a[c[f]+"RequestAnimationFrame"],e=a[c[f]+"CancelRequestAnimationFrame"];d&&e||(d=function(a){var c=+Date.now(),d=Math.max(b+16,c);return setTimeout(function(){a(b=d)},d-c)},e=clearTimeout),a.requestAnimationFrame=d,a.cancelAnimationFrame=e}(window),Materialize.guid=function(){function a(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}return function(){return a()+a()+"-"+a()+"-"+a()+"-"+a()+"-"+a()+a()+a()}}(),Materialize.escapeHash=function(a){return a.replace(/(:|\.|\[|\]|,|=)/g,"\\$1")},Materialize.elementOrParentIsFixed=function(a){var b=$(a),c=b.add(b.parents()),d=!1;return c.each(function(){if("fixed"===$(this).css("position"))return d=!0,!1}),d};var getTime=Date.now||function(){return(new Date).getTime()};Materialize.throttle=function(a,b,c){var d,e,f,g=null,h=0;c||(c={});var i=function(){h=c.leading===!1?0:getTime(),g=null,f=a.apply(d,e),d=e=null};return function(){var j=getTime();h||c.leading!==!1||(h=j);var k=b-(j-h);return d=this,e=arguments,k<=0?(clearTimeout(g),g=null,h=j,f=a.apply(d,e),d=e=null):g||c.trailing===!1||(g=setTimeout(i,k)),f}};var Vel;Vel=jQuery?jQuery.Velocity:$?$.Velocity:Velocity,function(a){a.fn.collapsible=function(b){var c={accordion:void 0,onOpen:void 0,onClose:void 0};return b=a.extend(c,b),this.each(function(){function c(b){j=i.find("> li > .collapsible-header"),b.hasClass("active")?b.parent().addClass("active"):b.parent().removeClass("active"),b.parent().hasClass("active")?b.siblings(".collapsible-body").stop(!0,!1).slideDown({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}}):b.siblings(".collapsible-body").stop(!0,!1).slideUp({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}}),j.not(b).removeClass("active").parent().removeClass("active"),j.not(b).parent().children(".collapsible-body").stop(!0,!1).each(function(){a(this).is(":visible")&&a(this).slideUp({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height",""),f(a(this).siblings(".collapsible-header"))}})})}function d(b){b.hasClass("active")?b.parent().addClass("active"):b.parent().removeClass("active"),b.parent().hasClass("active")?b.siblings(".collapsible-body").stop(!0,!1).slideDown({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}}):b.siblings(".collapsible-body").stop(!0,!1).slideUp({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}})}function e(a){b.accordion||"accordion"===k||void 0===k?c(a):d(a),f(a)}function f(a){a.hasClass("active")?"function"==typeof b.onOpen&&b.onOpen.call(this,a.parent()):"function"==typeof b.onClose&&b.onClose.call(this,a.parent())}function g(a){var b=h(a);return b.length>0}function h(a){return a.closest("li > .collapsible-header")}var i=a(this),j=a(this).find("> li > .collapsible-header"),k=i.data("collapsible");i.off("click.collapse","> li > .collapsible-header"),j.off("click.collapse"),i.on("click.collapse","> li > .collapsible-header",function(b){var c=a(b.target);g(c)&&(c=h(c)),c.toggleClass("active"),e(c)}),b.accordion||"accordion"===k||void 0===k?e(j.filter(".active").first()):j.filter(".active").each(function(){e(a(this))})})},a(document).ready(function(){a(".collapsible").collapsible()})}(jQuery),function(a){a.fn.scrollTo=function(b){return a(this).scrollTop(a(this).scrollTop()-a(this).offset().top+a(b).offset().top),this},a.fn.dropdown=function(b){var c={inDuration:300,outDuration:225,constrainWidth:!0,hover:!1,gutter:0,belowOrigin:!1,alignment:"left",stopPropagation:!1};return"open"===b?(this.each(function(){a(this).trigger("open")}),!1):"close"===b?(this.each(function(){a(this).trigger("close")}),!1):void this.each(function(){function d(){void 0!==g.data("induration")&&(h.inDuration=g.data("induration")),void 0!==g.data("outduration")&&(h.outDuration=g.data("outduration")),void 0!==g.data("constrainwidth")&&(h.constrainWidth=g.data("constrainwidth")),void 0!==g.data("hover")&&(h.hover=g.data("hover")),void 0!==g.data("gutter")&&(h.gutter=g.data("gutter")),void 0!==g.data("beloworigin")&&(h.belowOrigin=g.data("beloworigin")),void 0!==g.data("alignment")&&(h.alignment=g.data("alignment")),void 0!==g.data("stoppropagation")&&(h.stopPropagation=g.data("stoppropagation"))}function e(b){"focus"===b&&(i=!0),d(),j.addClass("active"),g.addClass("active"),h.constrainWidth===!0?j.css("width",g.outerWidth()):j.css("white-space","nowrap");var c=window.innerHeight,e=g.innerHeight(),k=g.offset().left,l=g.offset().top-a(window).scrollTop(),m=h.alignment,n=0,o=0,p=0;h.belowOrigin===!0&&(p=e);var q=0,r=0,s=g.parent();if(s.is("body")||(s[0].scrollHeight>s[0].clientHeight&&(q=s[0].scrollTop),s[0].scrollWidth>s[0].clientWidth&&(r=s[0].scrollLeft)),k+j.innerWidth()>a(window).width()?m="right":k-j.innerWidth()+g.innerWidth()<0&&(m="left"),l+j.innerHeight()>c)if(l+e-j.innerHeight()<0){var t=c-l-p;j.css("max-height",t)}else p||(p+=e),p-=j.innerHeight();if("left"===m)n=h.gutter,o=g.position().left+n;else if("right"===m){var u=g.position().left+g.outerWidth()-j.outerWidth();n=-h.gutter,o=u+n}j.css({position:"absolute",top:g.position().top+p+q,left:o+r}),j.stop(!0,!0).css("opacity",0).slideDown({queue:!1,duration:h.inDuration,easing:"easeOutCubic",complete:function(){a(this).css("height","")}}).animate({opacity:1},{queue:!1,duration:h.inDuration,easing:"easeOutSine"}),a(document).bind("click."+j.attr("id")+" touchstart."+j.attr("id"),function(b){j.is(b.target)||g.is(b.target)||g.find(b.target).length||(f(),a(document).unbind("click."+j.attr("id")+" touchstart."+j.attr("id")))})}function f(){i=!1,j.fadeOut(h.outDuration),j.removeClass("active"),g.removeClass("active"),a(document).unbind("click."+j.attr("id")+" touchstart."+j.attr("id")),setTimeout(function(){j.css("max-height","")},h.outDuration)}var g=a(this),h=a.extend({},c,b),i=!1,j=a("#"+g.attr("data-activates"));if(d(),g.after(j),h.hover){var k=!1;g.unbind("click."+g.attr("id")),g.on("mouseenter",function(a){k===!1&&(e(),k=!0)}),g.on("mouseleave",function(b){var c=b.toElement||b.relatedTarget;a(c).closest(".dropdown-content").is(j)||(j.stop(!0,!0),f(),k=!1)}),j.on("mouseleave",function(b){var c=b.toElement||b.relatedTarget;a(c).closest(".dropdown-button").is(g)||(j.stop(!0,!0),f(),k=!1)})}else g.unbind("click."+g.attr("id")),g.bind("click."+g.attr("id"),function(b){i||(g[0]!=b.currentTarget||g.hasClass("active")||0!==a(b.target).closest(".dropdown-content").length?g.hasClass("active")&&(f(),a(document).unbind("click."+j.attr("id")+" touchstart."+j.attr("id"))):(b.preventDefault(),h.stopPropagation&&b.stopPropagation(),e("click")))});g.on("open",function(a,b){e(b)}),g.on("close",f)})},a(document).ready(function(){a(".dropdown-button").dropdown()})}(jQuery),function(a){var b=0,c=0,d=function(){return c++,"materialize-modal-overlay-"+c},e={init:function(c){var e={opacity:.5,inDuration:350,outDuration:250,ready:void 0,
-complete:void 0,dismissible:!0,startingTop:"4%",endingTop:"10%"};return c=a.extend(e,c),this.each(function(){var e=a(this),f=a(this).attr("id")||"#"+a(this).data("target"),g=function(){var d=e.data("overlay-id"),f=a("#"+d);e.removeClass("open"),a("body").css({overflow:"",width:""}),e.find(".modal-close").off("click.close"),a(document).off("keyup.modal"+d),f.velocity({opacity:0},{duration:c.outDuration,queue:!1,ease:"easeOutQuart"});var g={duration:c.outDuration,queue:!1,ease:"easeOutCubic",complete:function(){a(this).css({display:"none"}),"function"==typeof c.complete&&c.complete.call(this,e),f.remove(),b--}};e.hasClass("bottom-sheet")?e.velocity({bottom:"-100%",opacity:0},g):e.velocity({top:c.startingTop,opacity:0,scaleX:.7},g)},h=function(f){var h=a("body"),i=h.innerWidth();if(h.css("overflow","hidden"),h.width(i),!e.hasClass("open")){var j=d(),k=a('<div class="modal-overlay"></div>');lStack=++b,k.attr("id",j).css("z-index",1e3+2*lStack),e.data("overlay-id",j).css("z-index",1e3+2*lStack+1),e.addClass("open"),a("body").append(k),c.dismissible&&(k.click(function(){g()}),a(document).on("keyup.modal"+j,function(a){27===a.keyCode&&g()})),e.find(".modal-close").on("click.close",function(a){g()}),k.css({display:"block",opacity:0}),e.css({display:"block",opacity:0}),k.velocity({opacity:c.opacity},{duration:c.inDuration,queue:!1,ease:"easeOutCubic"}),e.data("associated-overlay",k[0]);var l={duration:c.inDuration,queue:!1,ease:"easeOutCubic",complete:function(){"function"==typeof c.ready&&c.ready.call(this,e,f)}};e.hasClass("bottom-sheet")?e.velocity({bottom:"0",opacity:1},l):(a.Velocity.hook(e,"scaleX",.7),e.css({top:c.startingTop}),e.velocity({top:c.endingTop,opacity:1,scaleX:"1"},l))}};a(document).off("click.modalTrigger",'a[href="#'+f+'"], [data-target="'+f+'"]'),a(this).off("openModal"),a(this).off("closeModal"),a(document).on("click.modalTrigger",'a[href="#'+f+'"], [data-target="'+f+'"]',function(b){c.startingTop=(a(this).offset().top-a(window).scrollTop())/1.15,h(a(this)),b.preventDefault()}),a(this).on("openModal",function(){a(this).attr("href")||"#"+a(this).data("target");h()}),a(this).on("closeModal",function(){g()})})},open:function(){a(this).trigger("openModal")},close:function(){a(this).trigger("closeModal")}};a.fn.modal=function(b){return e[b]?e[b].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof b&&b?void a.error("Method "+b+" does not exist on jQuery.modal"):e.init.apply(this,arguments)}}(jQuery),function(a){a.fn.materialbox=function(){return this.each(function(){function b(){f=!1;var b=i.parent(".material-placeholder"),d=(window.innerWidth,window.innerHeight,i.data("width")),g=i.data("height");i.velocity("stop",!0),a("#materialbox-overlay").velocity("stop",!0),a(".materialbox-caption").velocity("stop",!0),a("#materialbox-overlay").velocity({opacity:0},{duration:h,queue:!1,easing:"easeOutQuad",complete:function(){e=!1,a(this).remove()}}),i.velocity({width:d,height:g,left:0,top:0},{duration:h,queue:!1,easing:"easeOutQuad"}),a(".materialbox-caption").velocity({opacity:0},{duration:h,queue:!1,easing:"easeOutQuad",complete:function(){b.css({height:"",width:"",position:"",top:"",left:""}),i.css({height:"",top:"",left:"",width:"","max-width":"",position:"","z-index":"","will-change":""}),i.removeClass("active"),f=!0,a(this).remove(),c&&c.css("overflow","")}})}if(!a(this).hasClass("initialized")){a(this).addClass("initialized");var c,d,e=!1,f=!0,g=275,h=200,i=a(this),j=a("<div></div>").addClass("material-placeholder");i.wrap(j),i.on("click",function(){var h=i.parent(".material-placeholder"),j=window.innerWidth,k=window.innerHeight,l=i.width(),m=i.height();if(f===!1)return b(),!1;if(e&&f===!0)return b(),!1;f=!1,i.addClass("active"),e=!0,h.css({width:h[0].getBoundingClientRect().width,height:h[0].getBoundingClientRect().height,position:"relative",top:0,left:0}),c=void 0,d=h[0].parentNode;for(;null!==d&&!a(d).is(document);){var n=a(d);"visible"!==n.css("overflow")&&(n.css("overflow","visible"),c=void 0===c?n:c.add(n)),d=d.parentNode}i.css({position:"absolute","z-index":1e3,"will-change":"left, top, width, height"}).data("width",l).data("height",m);var o=a('<div id="materialbox-overlay"></div>').css({opacity:0}).click(function(){f===!0&&b()});i.before(o);var p=o[0].getBoundingClientRect();if(o.css({width:j,height:k,left:-1*p.left,top:-1*p.top}),o.velocity({opacity:1},{duration:g,queue:!1,easing:"easeOutQuad"}),""!==i.data("caption")){var q=a('<div class="materialbox-caption"></div>');q.text(i.data("caption")),a("body").append(q),q.css({display:"inline"}),q.velocity({opacity:1},{duration:g,queue:!1,easing:"easeOutQuad"})}var r=0,s=l/j,t=m/k,u=0,v=0;s>t?(r=m/l,u=.9*j,v=.9*j*r):(r=l/m,u=.9*k*r,v=.9*k),i.hasClass("responsive-img")?i.velocity({"max-width":u,width:l},{duration:0,queue:!1,complete:function(){i.css({left:0,top:0}).velocity({height:v,width:u,left:a(document).scrollLeft()+j/2-i.parent(".material-placeholder").offset().left-u/2,top:a(document).scrollTop()+k/2-i.parent(".material-placeholder").offset().top-v/2},{duration:g,queue:!1,easing:"easeOutQuad",complete:function(){f=!0}})}}):i.css("left",0).css("top",0).velocity({height:v,width:u,left:a(document).scrollLeft()+j/2-i.parent(".material-placeholder").offset().left-u/2,top:a(document).scrollTop()+k/2-i.parent(".material-placeholder").offset().top-v/2},{duration:g,queue:!1,easing:"easeOutQuad",complete:function(){f=!0}})}),a(window).scroll(function(){e&&b()}),a(document).keyup(function(a){27===a.keyCode&&f===!0&&e&&b()})}})},a(document).ready(function(){a(".materialboxed").materialbox()})}(jQuery),function(a){a.fn.parallax=function(){var b=a(window).width();return this.each(function(c){function d(c){var d;d=b<601?e.height()>0?e.height():e.children("img").height():e.height()>0?e.height():500;var f=e.children("img").first(),g=f.height(),h=g-d,i=e.offset().top+d,j=e.offset().top,k=a(window).scrollTop(),l=window.innerHeight,m=k+l,n=(m-j)/(d+l),o=Math.round(h*n);c&&f.css("display","block"),i>k&&j<k+l&&f.css("transform","translate3D(-50%,"+o+"px, 0)")}var e=a(this);e.addClass("parallax"),e.children("img").one("load",function(){d(!0)}).each(function(){this.complete&&a(this).trigger("load")}),a(window).scroll(function(){b=a(window).width(),d(!1)}),a(window).resize(function(){b=a(window).width(),d(!1)})})}}(jQuery),function(a){var b={init:function(b){var c={onShow:null,swipeable:!1,responsiveThreshold:1/0};return b=a.extend(c,b),this.each(function(){var c,d,e,f,g,h=a(this),i=a(window).width(),j=h.find("li.tab a"),k=h.width(),l=a(),m=Math.max(k,h[0].scrollWidth)/j.length,n=prev_index=0,o=!1,p=300,q=function(a){return k-a.position().left-a.outerWidth()-h.scrollLeft()},r=function(a){return a.position().left+h.scrollLeft()},s=function(a){n-a>=0?(f.velocity({right:q(c)},{duration:p,queue:!1,easing:"easeOutQuad"}),f.velocity({left:r(c)},{duration:p,queue:!1,easing:"easeOutQuad",delay:90})):(f.velocity({left:r(c)},{duration:p,queue:!1,easing:"easeOutQuad"}),f.velocity({right:q(c)},{duration:p,queue:!1,easing:"easeOutQuad",delay:90}))};b.swipeable&&i>b.responsiveThreshold&&(b.swipeable=!1),c=a(j.filter('[href="'+location.hash+'"]')),0===c.length&&(c=a(this).find("li.tab a.active").first()),0===c.length&&(c=a(this).find("li.tab a").first()),c.addClass("active"),n=j.index(c),n<0&&(n=0),void 0!==c[0]&&(d=a(c[0].hash),d.addClass("active")),h.find(".indicator").length||h.append('<div class="indicator"></div>'),f=h.find(".indicator"),h.append(f),h.is(":visible")&&setTimeout(function(){f.css({right:q(c)}),f.css({left:r(c)})},0),a(window).resize(function(){k=h.width(),m=Math.max(k,h[0].scrollWidth)/j.length,n<0&&(n=0),0!==m&&0!==k&&(f.css({right:q(c)}),f.css({left:r(c)}))}),b.swipeable?(j.each(function(){var b=a(Materialize.escapeHash(this.hash));b.addClass("carousel-item"),l=l.add(b)}),e=l.wrapAll('<div class="tabs-content carousel"></div>'),l.css("display",""),a(".tabs-content.carousel").carousel({fullWidth:!0,noWrap:!0,onCycleTo:function(a){if(!o){var b=n;n=e.index(a),c=j.eq(n),s(b)}}})):j.not(c).each(function(){a(Materialize.escapeHash(this.hash)).hide()}),h.on("click","a",function(e){if(a(this).parent().hasClass("disabled"))return void e.preventDefault();if(!a(this).attr("target")){o=!0,k=h.width(),m=Math.max(k,h[0].scrollWidth)/j.length,c.removeClass("active");var f=d;c=a(this),d=a(Materialize.escapeHash(this.hash)),j=h.find("li.tab a");c.position();c.addClass("active"),prev_index=n,n=j.index(a(this)),n<0&&(n=0),b.swipeable?l.length&&l.carousel("set",n):(void 0!==d&&(d.show(),d.addClass("active"),"function"==typeof b.onShow&&b.onShow.call(this,d)),void 0===f||f.is(d)||(f.hide(),f.removeClass("active"))),g=setTimeout(function(){o=!1},p),s(prev_index),e.preventDefault()}})})},select_tab:function(a){this.find('a[href="#'+a+'"]').trigger("click")}};a.fn.tabs=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.tabs"):b.init.apply(this,arguments)},a(document).ready(function(){a("ul.tabs").tabs()})}(jQuery),function(a){a.fn.tooltip=function(c){var d=5,e={delay:350,tooltip:"",position:"bottom",html:!1};return"remove"===c?(this.each(function(){a("#"+a(this).attr("data-tooltip-id")).remove(),a(this).off("mouseenter.tooltip mouseleave.tooltip")}),!1):(c=a.extend(e,c),this.each(function(){var e=Materialize.guid(),f=a(this);f.attr("data-tooltip-id")&&a("#"+f.attr("data-tooltip-id")).remove(),f.attr("data-tooltip-id",e);var g,h,i,j,k,l,m=function(){g=f.attr("data-html")?"true"===f.attr("data-html"):c.html,h=f.attr("data-delay"),h=void 0===h||""===h?c.delay:h,i=f.attr("data-position"),i=void 0===i||""===i?c.position:i,j=f.attr("data-tooltip"),j=void 0===j||""===j?c.tooltip:j};m();var n=function(){var b=a('<div class="material-tooltip"></div>');return j=g?a("<span></span>").html(j):a("<span></span>").text(j),b.append(j).appendTo(a("body")).attr("id",e),l=a('<div class="backdrop"></div>'),l.appendTo(b),b};k=n(),f.off("mouseenter.tooltip mouseleave.tooltip");var o,p=!1;f.on({"mouseenter.tooltip":function(a){var c=function(){m(),p=!0,k.velocity("stop"),l.velocity("stop"),k.css({visibility:"visible",left:"0px",top:"0px"});var a,c,e,g=f.outerWidth(),h=f.outerHeight(),j=k.outerHeight(),n=k.outerWidth(),o="0px",q="0px",r=l[0].offsetWidth,s=l[0].offsetHeight,t=8,u=8,v=0;"top"===i?(a=f.offset().top-j-d,c=f.offset().left+g/2-n/2,e=b(c,a,n,j),o="-10px",l.css({bottom:0,left:0,borderRadius:"14px 14px 0 0",transformOrigin:"50% 100%",marginTop:j,marginLeft:n/2-r/2})):"left"===i?(a=f.offset().top+h/2-j/2,c=f.offset().left-n-d,e=b(c,a,n,j),q="-10px",l.css({top:"-7px",right:0,width:"14px",height:"14px",borderRadius:"14px 0 0 14px",transformOrigin:"95% 50%",marginTop:j/2,marginLeft:n})):"right"===i?(a=f.offset().top+h/2-j/2,c=f.offset().left+g+d,e=b(c,a,n,j),q="+10px",l.css({top:"-7px",left:0,width:"14px",height:"14px",borderRadius:"0 14px 14px 0",transformOrigin:"5% 50%",marginTop:j/2,marginLeft:"0px"})):(a=f.offset().top+f.outerHeight()+d,c=f.offset().left+g/2-n/2,e=b(c,a,n,j),o="+10px",l.css({top:0,left:0,marginLeft:n/2-r/2})),k.css({top:e.y,left:e.x}),t=Math.SQRT2*n/parseInt(r),u=Math.SQRT2*j/parseInt(s),v=Math.max(t,u),k.velocity({translateY:o,translateX:q},{duration:350,queue:!1}).velocity({opacity:1},{duration:300,delay:50,queue:!1}),l.css({visibility:"visible"}).velocity({opacity:1},{duration:55,delay:0,queue:!1}).velocity({scaleX:v,scaleY:v},{duration:300,delay:0,queue:!1,easing:"easeInOutQuad"})};o=setTimeout(c,h)},"mouseleave.tooltip":function(){p=!1,clearTimeout(o),setTimeout(function(){p!==!0&&(k.velocity({opacity:0,translateY:0,translateX:0},{duration:225,queue:!1}),l.velocity({opacity:0,scaleX:1,scaleY:1},{duration:225,queue:!1,complete:function(){l.css({visibility:"hidden"}),k.css({visibility:"hidden"}),p=!1}}))},225)}})}))};var b=function(b,c,d,e){var f=b,g=c;return f<0?f=4:f+d>window.innerWidth&&(f-=f+d-window.innerWidth),g<0?g=4:g+e>window.innerHeight+a(window).scrollTop&&(g-=g+e-window.innerHeight),{x:f,y:g}};a(document).ready(function(){a(".tooltipped").tooltip()})}(jQuery),function(a){"use strict";function b(a){return null!==a&&a===a.window}function c(a){return b(a)?a:9===a.nodeType&&a.defaultView}function d(a){var b,d,e={top:0,left:0},f=a&&a.ownerDocument;return b=f.documentElement,"undefined"!=typeof a.getBoundingClientRect&&(e=a.getBoundingClientRect()),d=c(f),{top:e.top+d.pageYOffset-b.clientTop,left:e.left+d.pageXOffset-b.clientLeft}}function e(a){var b="";for(var c in a)a.hasOwnProperty(c)&&(b+=c+":"+a[c]+";");return b}function f(a){if(k.allowEvent(a)===!1)return null;for(var b=null,c=a.target||a.srcElement;null!==c.parentElement;){if(!(c instanceof SVGElement||c.className.indexOf("waves-effect")===-1)){b=c;break}if(c.classList.contains("waves-effect")){b=c;break}c=c.parentElement}return b}function g(b){var c=f(b);null!==c&&(j.show(b,c),"ontouchstart"in a&&(c.addEventListener("touchend",j.hide,!1),c.addEventListener("touchcancel",j.hide,!1)),c.addEventListener("mouseup",j.hide,!1),c.addEventListener("mouseleave",j.hide,!1))}var h=h||{},i=document.querySelectorAll.bind(document),j={duration:750,show:function(a,b){if(2===a.button)return!1;var c=b||this,f=document.createElement("div");f.className="waves-ripple",c.appendChild(f);var g=d(c),h=a.pageY-g.top,i=a.pageX-g.left,k="scale("+c.clientWidth/100*10+")";"touches"in a&&(h=a.touches[0].pageY-g.top,i=a.touches[0].pageX-g.left),f.setAttribute("data-hold",Date.now()),f.setAttribute("data-scale",k),f.setAttribute("data-x",i),f.setAttribute("data-y",h);var l={top:h+"px",left:i+"px"};f.className=f.className+" waves-notransition",f.setAttribute("style",e(l)),f.className=f.className.replace("waves-notransition",""),l["-webkit-transform"]=k,l["-moz-transform"]=k,l["-ms-transform"]=k,l["-o-transform"]=k,l.transform=k,l.opacity="1",l["-webkit-transition-duration"]=j.duration+"ms",l["-moz-transition-duration"]=j.duration+"ms",l["-o-transition-duration"]=j.duration+"ms",l["transition-duration"]=j.duration+"ms",l["-webkit-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",l["-moz-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",l["-o-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",l["transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",f.setAttribute("style",e(l))},hide:function(a){k.touchup(a);var b=this,c=(1.4*b.clientWidth,null),d=b.getElementsByClassName("waves-ripple");if(!(d.length>0))return!1;c=d[d.length-1];var f=c.getAttribute("data-x"),g=c.getAttribute("data-y"),h=c.getAttribute("data-scale"),i=Date.now()-Number(c.getAttribute("data-hold")),l=350-i;l<0&&(l=0),setTimeout(function(){var a={top:g+"px",left:f+"px",opacity:"0","-webkit-transition-duration":j.duration+"ms","-moz-transition-duration":j.duration+"ms","-o-transition-duration":j.duration+"ms","transition-duration":j.duration+"ms","-webkit-transform":h,"-moz-transform":h,"-ms-transform":h,"-o-transform":h,transform:h};c.setAttribute("style",e(a)),setTimeout(function(){try{b.removeChild(c)}catch(a){return!1}},j.duration)},l)},wrapInput:function(a){for(var b=0;b<a.length;b++){var c=a[b];if("input"===c.tagName.toLowerCase()){var d=c.parentNode;if("i"===d.tagName.toLowerCase()&&d.className.indexOf("waves-effect")!==-1)continue;var e=document.createElement("i");e.className=c.className+" waves-input-wrapper";var f=c.getAttribute("style");f||(f=""),e.setAttribute("style",f),c.className="waves-button-input",c.removeAttribute("style"),d.replaceChild(e,c),e.appendChild(c)}}}},k={touches:0,allowEvent:function(a){var b=!0;return"touchstart"===a.type?k.touches+=1:"touchend"===a.type||"touchcancel"===a.type?setTimeout(function(){k.touches>0&&(k.touches-=1)},500):"mousedown"===a.type&&k.touches>0&&(b=!1),b},touchup:function(a){k.allowEvent(a)}};h.displayEffect=function(b){b=b||{},"duration"in b&&(j.duration=b.duration),j.wrapInput(i(".waves-effect")),"ontouchstart"in a&&document.body.addEventListener("touchstart",g,!1),document.body.addEventListener("mousedown",g,!1)},h.attach=function(b){"input"===b.tagName.toLowerCase()&&(j.wrapInput([b]),b=b.parentElement),"ontouchstart"in a&&b.addEventListener("touchstart",g,!1),b.addEventListener("mousedown",g,!1)},a.Waves=h,document.addEventListener("DOMContentLoaded",function(){h.displayEffect()},!1)}(window),Materialize.toast=function(a,b,c,d){function e(a){var b=document.createElement("div");if(b.classList.add("toast"),c)for(var e=c.split(" "),f=0,g=e.length;f<g;f++)b.classList.add(e[f]);("object"==typeof HTMLElement?a instanceof HTMLElement:a&&"object"==typeof a&&null!==a&&1===a.nodeType&&"string"==typeof a.nodeName)?b.appendChild(a):a instanceof jQuery?b.appendChild(a[0]):b.innerHTML=a;var h=new Hammer(b,{prevent_default:!1});return h.on("pan",function(a){var c=a.deltaX,d=80;b.classList.contains("panning")||b.classList.add("panning");var e=1-Math.abs(c/d);e<0&&(e=0),Vel(b,{left:c,opacity:e},{duration:50,queue:!1,easing:"easeOutQuad"})}),h.on("panend",function(a){var c=a.deltaX,e=80;Math.abs(c)>e?Vel(b,{marginTop:"-40px"},{duration:375,easing:"easeOutExpo",queue:!1,complete:function(){"function"==typeof d&&d(),b.parentNode.removeChild(b)}}):(b.classList.remove("panning"),Vel(b,{left:0,opacity:1},{duration:300,easing:"easeOutExpo",queue:!1}))}),b}c=c||"";var f=document.getElementById("toast-container");null===f&&(f=document.createElement("div"),f.id="toast-container",document.body.appendChild(f));var g=e(a);a&&f.appendChild(g),g.style.opacity=0,Vel(g,{translateY:"-35px",opacity:1},{duration:300,easing:"easeOutCubic",queue:!1});var h,i=b;null!=i&&(h=setInterval(function(){null===g.parentNode&&window.clearInterval(h),g.classList.contains("panning")||(i-=20),i<=0&&(Vel(g,{opacity:0,marginTop:"-40px"},{duration:375,easing:"easeOutExpo",queue:!1,complete:function(){"function"==typeof d&&d(),this[0].parentNode.removeChild(this[0])}}),window.clearInterval(h))},20))},function(a){var b={init:function(b){var c={menuWidth:300,edge:"left",closeOnClick:!1,draggable:!0};b=a.extend(c,b),a(this).each(function(){var c=a(this),d=c.attr("data-activates"),e=a("#"+d);300!=b.menuWidth&&e.css("width",b.menuWidth);var f=a('.drag-target[data-sidenav="'+d+'"]');b.draggable?(f.length&&f.remove(),f=a('<div class="drag-target"></div>').attr("data-sidenav",d),a("body").append(f)):f=a(),"left"==b.edge?(e.css("transform","translateX(-100%)"),f.css({left:0})):(e.addClass("right-aligned").css("transform","translateX(100%)"),f.css({right:0})),e.hasClass("fixed")&&window.innerWidth>992&&e.css("transform","translateX(0)"),e.hasClass("fixed")&&a(window).resize(function(){window.innerWidth>992?0!==a("#sidenav-overlay").length&&i?g(!0):e.css("transform","translateX(0%)"):i===!1&&("left"===b.edge?e.css("transform","translateX(-100%)"):e.css("transform","translateX(100%)"))}),b.closeOnClick===!0&&e.on("click.itemclick","a:not(.collapsible-header)",function(){g()});var g=function(c){h=!1,i=!1,a("body").css({overflow:"",width:""}),a("#sidenav-overlay").velocity({opacity:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}}),"left"===b.edge?(f.css({width:"",right:"",left:"0"}),e.velocity({translateX:"-100%"},{duration:200,queue:!1,easing:"easeOutCubic",complete:function(){c===!0&&(e.removeAttr("style"),e.css("width",b.menuWidth))}})):(f.css({width:"",right:"0",left:""}),e.velocity({translateX:"100%"},{duration:200,queue:!1,easing:"easeOutCubic",complete:function(){c===!0&&(e.removeAttr("style"),e.css("width",b.menuWidth))}}))},h=!1,i=!1;b.draggable&&(f.on("click",function(){i&&g()}),f.hammer({prevent_default:!1}).bind("pan",function(c){if("touch"==c.gesture.pointerType){var d=(c.gesture.direction,c.gesture.center.x),f=(c.gesture.center.y,c.gesture.velocityX,a("body")),h=a("#sidenav-overlay"),j=f.innerWidth();if(f.css("overflow","hidden"),f.width(j),0===h.length&&(h=a('<div id="sidenav-overlay"></div>'),h.css("opacity",0).click(function(){g()}),a("body").append(h)),"left"===b.edge&&(d>b.menuWidth?d=b.menuWidth:d<0&&(d=0)),"left"===b.edge)d<b.menuWidth/2?i=!1:d>=b.menuWidth/2&&(i=!0),e.css("transform","translateX("+(d-b.menuWidth)+"px)");else{d<window.innerWidth-b.menuWidth/2?i=!0:d>=window.innerWidth-b.menuWidth/2&&(i=!1);var k=d-b.menuWidth/2;k<0&&(k=0),e.css("transform","translateX("+k+"px)")}var l;"left"===b.edge?(l=d/b.menuWidth,h.velocity({opacity:l},{duration:10,queue:!1,easing:"easeOutQuad"})):(l=Math.abs((d-window.innerWidth)/b.menuWidth),h.velocity({opacity:l},{duration:10,queue:!1,easing:"easeOutQuad"}))}}).bind("panend",function(c){if("touch"==c.gesture.pointerType){var d=a('<div id="sidenav-overlay"></div>'),g=c.gesture.velocityX,j=c.gesture.center.x,k=j-b.menuWidth,l=j-b.menuWidth/2;k>0&&(k=0),l<0&&(l=0),h=!1,"left"===b.edge?i&&g<=.3||g<-.5?(0!==k&&e.velocity({translateX:[0,k]},{duration:300,queue:!1,easing:"easeOutQuad"}),d.velocity({opacity:1},{duration:50,queue:!1,easing:"easeOutQuad"}),f.css({width:"50%",right:0,left:""}),i=!0):(!i||g>.3)&&(a("body").css({overflow:"",width:""}),e.velocity({translateX:[-1*b.menuWidth-10,k]},{duration:200,queue:!1,easing:"easeOutQuad"}),d.velocity({opacity:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}}),f.css({width:"10px",right:"",left:0})):i&&g>=-.3||g>.5?(0!==l&&e.velocity({translateX:[0,l]},{duration:300,queue:!1,easing:"easeOutQuad"}),d.velocity({opacity:1},{duration:50,queue:!1,easing:"easeOutQuad"}),f.css({width:"50%",right:"",left:0}),i=!0):(!i||g<-.3)&&(a("body").css({overflow:"",width:""}),e.velocity({translateX:[b.menuWidth+10,l]},{duration:200,queue:!1,easing:"easeOutQuad"}),d.velocity({opacity:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}}),f.css({width:"10px",right:0,left:""}))}})),c.off("click.sidenav").on("click.sidenav",function(){if(i===!0)i=!1,h=!1,g();else{var c=a("body"),d=a('<div id="sidenav-overlay"></div>'),j=c.innerWidth();c.css("overflow","hidden"),c.width(j),a("body").append(f),"left"===b.edge?(f.css({width:"50%",right:0,left:""}),e.velocity({translateX:[0,-1*b.menuWidth]},{duration:300,queue:!1,easing:"easeOutQuad"})):(f.css({width:"50%",right:"",left:0}),e.velocity({translateX:[0,b.menuWidth]},{duration:300,queue:!1,easing:"easeOutQuad"})),d.css("opacity",0).click(function(){i=!1,h=!1,g(),d.velocity({opacity:0},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}})}),a("body").append(d),d.velocity({opacity:1},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){i=!0,h=!1}})}return!1})})},destroy:function(){var b=a("#sidenav-overlay"),c=a('.drag-target[data-sidenav="'+a(this).attr("data-activates")+'"]');b.trigger("click"),c.remove(),a(this).off("click"),b.remove()},show:function(){this.trigger("click")},hide:function(){a("#sidenav-overlay").trigger("click")}};a.fn.sideNav=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.sideNav"):b.init.apply(this,arguments)}}(jQuery),function(a){function b(b,c,d,e){var g=a();return a.each(f,function(a,f){if(f.height()>0){var h=f.offset().top,i=f.offset().left,j=i+f.width(),k=h+f.height(),l=!(i>c||j<e||h>d||k<b);l&&g.push(f)}}),g}function c(c){++i;var d=e.scrollTop(),f=e.scrollLeft(),h=f+e.width(),k=d+e.height(),l=b(d+j.top+c||200,h+j.right,k+j.bottom,f+j.left);a.each(l,function(a,b){var c=b.data("scrollSpy:ticks");"number"!=typeof c&&b.triggerHandler("scrollSpy:enter"),b.data("scrollSpy:ticks",i)}),a.each(g,function(a,b){var c=b.data("scrollSpy:ticks");"number"==typeof c&&c!==i&&(b.triggerHandler("scrollSpy:exit"),b.data("scrollSpy:ticks",null))}),g=l}function d(){e.trigger("scrollSpy:winSize")}var e=a(window),f=[],g=[],h=!1,i=0,j={top:0,right:0,bottom:0,left:0};a.scrollSpy=function(b,d){var g={throttle:100,scrollOffset:200};d=a.extend(g,d);var i=[];b=a(b),b.each(function(b,c){f.push(a(c)),a(c).data("scrollSpy:id",b),a('a[href="#'+a(c).attr("id")+'"]').click(function(b){b.preventDefault();var c=a(Materialize.escapeHash(this.hash)).offset().top+1;a("html, body").animate({scrollTop:c-d.scrollOffset},{duration:400,queue:!1,easing:"easeOutCubic"})})}),j.top=d.offsetTop||0,j.right=d.offsetRight||0,j.bottom=d.offsetBottom||0,j.left=d.offsetLeft||0;var k=Materialize.throttle(function(){c(d.scrollOffset)},d.throttle||100),l=function(){a(document).ready(k)};return h||(e.on("scroll",l),e.on("resize",l),h=!0),setTimeout(l,0),b.on("scrollSpy:enter",function(){i=a.grep(i,function(a){return 0!=a.height()});var b=a(this);i[0]?(a('a[href="#'+i[0].attr("id")+'"]').removeClass("active"),b.data("scrollSpy:id")<i[0].data("scrollSpy:id")?i.unshift(a(this)):i.push(a(this))):i.push(a(this)),a('a[href="#'+i[0].attr("id")+'"]').addClass("active")}),b.on("scrollSpy:exit",function(){if(i=a.grep(i,function(a){return 0!=a.height()}),i[0]){a('a[href="#'+i[0].attr("id")+'"]').removeClass("active");var b=a(this);i=a.grep(i,function(a){return a.attr("id")!=b.attr("id")}),i[0]&&a('a[href="#'+i[0].attr("id")+'"]').addClass("active")}}),b},a.winSizeSpy=function(b){return a.winSizeSpy=function(){return e},b=b||{throttle:100},e.on("resize",Materialize.throttle(d,b.throttle||100))},a.fn.scrollSpy=function(b){return a.scrollSpy(a(this),b)}}(jQuery),function(a){a(document).ready(function(){function b(b){var c=b.css("font-family"),d=b.css("font-size"),f=b.css("line-height");d&&e.css("font-size",d),c&&e.css("font-family",c),f&&e.css("line-height",f),"off"===b.attr("wrap")&&e.css("overflow-wrap","normal").css("white-space","pre"),e.text(b.val()+"\n");var g=e.html().replace(/\n/g,"<br>");e.html(g),b.is(":visible")?e.css("width",b.width()):e.css("width",a(window).width()/2),b.css("height",e.height())}Materialize.updateTextFields=function(){var b="input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea";a(b).each(function(b,c){var d=a(this);a(c).val().length>0||c.autofocus||void 0!==d.attr("placeholder")?d.siblings("label").addClass("active"):a(c)[0].validity?d.siblings("label").toggleClass("active",a(c)[0].validity.badInput===!0):d.siblings("label").removeClass("active")})};var c="input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea";a(document).on("change",c,function(){0===a(this).val().length&&void 0===a(this).attr("placeholder")||a(this).siblings("label").addClass("active"),validate_field(a(this))}),a(document).ready(function(){Materialize.updateTextFields()}),a(document).on("reset",function(b){var d=a(b.target);d.is("form")&&(d.find(c).removeClass("valid").removeClass("invalid"),d.find(c).each(function(){""===a(this).attr("value")&&a(this).siblings("label").removeClass("active")}),d.find("select.initialized").each(function(){var a=d.find("option[selected]").text();d.siblings("input.select-dropdown").val(a)}))}),a(document).on("focus",c,function(){a(this).siblings("label, .prefix").addClass("active")}),a(document).on("blur",c,function(){var b=a(this),c=".prefix";0===b.val().length&&b[0].validity.badInput!==!0&&void 0===b.attr("placeholder")&&(c+=", label"),b.siblings(c).removeClass("active"),validate_field(b)}),window.validate_field=function(a){var b=void 0!==a.attr("data-length"),c=parseInt(a.attr("data-length")),d=a.val().length;0===a.val().length&&a[0].validity.badInput===!1?a.hasClass("validate")&&(a.removeClass("valid"),a.removeClass("invalid")):a.hasClass("validate")&&(a.is(":valid")&&b&&d<=c||a.is(":valid")&&!b?(a.removeClass("invalid"),a.addClass("valid")):(a.removeClass("valid"),a.addClass("invalid")))};var d="input[type=radio], input[type=checkbox]";a(document).on("keyup.radio",d,function(b){if(9===b.which){a(this).addClass("tabbed");var c=a(this);return void c.one("blur",function(b){a(this).removeClass("tabbed")})}});var e=a(".hiddendiv").first();e.length||(e=a('<div class="hiddendiv common"></div>'),a("body").append(e));var f=".materialize-textarea";a(f).each(function(){var c=a(this);c.val().length&&b(c)}),a("body").on("keyup keydown autoresize",f,function(){b(a(this))}),a(document).on("change",'.file-field input[type="file"]',function(){for(var b=a(this).closest(".file-field"),c=b.find("input.file-path"),d=a(this)[0].files,e=[],f=0;f<d.length;f++)e.push(d[f].name);c.val(e.join(", ")),c.trigger("change")});var g,h="input[type=range]",i=!1;a(h).each(function(){var b=a('<span class="thumb"><span class="value"></span></span>');a(this).after(b)});var j=".range-field";a(document).on("change",h,function(b){var c=a(this).siblings(".thumb");c.find(".value").html(a(this).val())}),a(document).on("input mousedown touchstart",h,function(b){var c=a(this).siblings(".thumb"),d=a(this).outerWidth();c.length<=0&&(c=a('<span class="thumb"><span class="value"></span></span>'),a(this).after(c)),c.find(".value").html(a(this).val()),i=!0,a(this).addClass("active"),c.hasClass("active")||c.velocity({height:"30px",width:"30px",top:"-20px",marginLeft:"-15px"},{duration:300,easing:"easeOutExpo"}),"input"!==b.type&&(g=void 0===b.pageX||null===b.pageX?b.originalEvent.touches[0].pageX-a(this).offset().left:b.pageX-a(this).offset().left,g<0?g=0:g>d&&(g=d),c.addClass("active").css("left",g)),c.find(".value").html(a(this).val())}),a(document).on("mouseup touchend",j,function(){i=!1,a(this).removeClass("active")}),a(document).on("mousemove touchmove",j,function(b){var c,d=a(this).children(".thumb");if(i){d.hasClass("active")||d.velocity({height:"30px",width:"30px",top:"-20px",marginLeft:"-15px"},{duration:300,easing:"easeOutExpo"}),c=void 0===b.pageX||null===b.pageX?b.originalEvent.touches[0].pageX-a(this).offset().left:b.pageX-a(this).offset().left;var e=a(this).outerWidth();c<0?c=0:c>e&&(c=e),d.addClass("active").css("left",c),d.find(".value").html(d.siblings(h).val())}}),a(document).on("mouseout touchleave",j,function(){if(!i){var b=a(this).children(".thumb");b.hasClass("active")&&b.velocity({height:"0",width:"0",top:"10px",marginLeft:"-6px"},{duration:100}),b.removeClass("active")}}),a.fn.autocomplete=function(b){var c={data:{},limit:1/0,onAutocomplete:null};return b=a.extend(c,b),this.each(function(){var c,d=a(this),e=b.data,f=0,g=0,h=d.closest(".input-field");if(!a.isEmptyObject(e)){var i,j=a('<ul class="autocomplete-content dropdown-content"></ul>');h.length?(i=h.children(".autocomplete-content.dropdown-content").first(),i.length||h.append(j)):(i=d.next(".autocomplete-content.dropdown-content"),i.length||d.after(j)),i.length&&(j=i);var k=function(a,b){var c=b.find("img"),d=b.text().toLowerCase().indexOf(""+a.toLowerCase()),e=d+a.length-1,f=b.text().slice(0,d),g=b.text().slice(d,e+1),h=b.text().slice(e+1);b.html("<span>"+f+"<span class='highlight'>"+g+"</span>"+h+"</span>"),c.length&&b.prepend(c)},l=function(){g=0,j.find(".active").removeClass("active")};d.off("keyup.autocomplete").on("keyup.autocomplete",function(g){if(f=0,13!==g.which&&38!==g.which&&40!==g.which){var h=d.val().toLowerCase();if(c!==h&&(j.empty(),l(),""!==h))for(var i in e)if(e.hasOwnProperty(i)&&i.toLowerCase().indexOf(h)!==-1&&i.toLowerCase()!==h){if(f>=b.limit)break;var m=a("<li></li>");e[i]?m.append('<img src="'+e[i]+'" class="right circle"><span>'+i+"</span>"):m.append("<span>"+i+"</span>"),j.append(m),k(h,m),f++}c=h}}),d.off("keydown.autocomplete").on("keydown.autocomplete",function(a){var b,c=a.which,d=j.children("li").length,e=j.children(".active").first();return 13===c?(b=j.children("li").eq(g),void(b.length&&(b.click(),a.preventDefault()))):void(38!==c&&40!==c||(a.preventDefault(),38===c&&g>0&&g--,40===c&&g<d-1&&e.length&&g++,e.removeClass("active"),j.children("li").eq(g).addClass("active")))}),j.on("click","li",function(){var c=a(this).text().trim();d.val(c),d.trigger("change"),j.empty(),l(),"function"==typeof b.onAutocomplete&&b.onAutocomplete.call(this,c)})}})}}),a.fn.material_select=function(b){function c(a,b,c){var e=a.indexOf(b),f=e===-1;return f?a.push(b):a.splice(e,1),c.siblings("ul.dropdown-content").find("li").eq(b).toggleClass("active"),c.find("option").eq(b).prop("selected",f),d(a,c),f}function d(a,b){
-for(var c="",d=0,e=a.length;d<e;d++){var f=b.find("option").eq(a[d]).text();c+=0===d?f:", "+f}""===c&&(c=b.find("option:disabled").eq(0).text()),b.siblings("input.select-dropdown").val(c)}a(this).each(function(){var d=a(this);if(!d.hasClass("browser-default")){var e=!!d.attr("multiple"),f=d.data("select-id");if(f&&(d.parent().find("span.caret").remove(),d.parent().find("input").remove(),d.unwrap(),a("ul#select-options-"+f).remove()),"destroy"===b)return void d.data("select-id",null).removeClass("initialized");var g=Materialize.guid();d.data("select-id",g);var h=a('<div class="select-wrapper"></div>');h.addClass(d.attr("class"));var i=a('<ul id="select-options-'+g+'" class="dropdown-content select-dropdown '+(e?"multiple-select-dropdown":"")+'"></ul>'),j=d.children("option, optgroup"),k=[],l=!1,m=d.find("option:selected").html()||d.find("option:first").html()||"",n=function(b,c,d){var e=c.is(":disabled")?"disabled ":"",f="optgroup-option"===d?"optgroup-option ":"",g=c.data("icon"),h=c.attr("class");if(g){var j="";return h&&(j=' class="'+h+'"'),"multiple"===d?i.append(a('<li class="'+e+'"><img alt="" src="'+g+'"'+j+'><span><input type="checkbox"'+e+"/><label></label>"+c.html()+"</span></li>")):i.append(a('<li class="'+e+f+'"><img alt="" src="'+g+'"'+j+"><span>"+c.html()+"</span></li>")),!0}"multiple"===d?i.append(a('<li class="'+e+'"><span><input type="checkbox"'+e+"/><label></label>"+c.html()+"</span></li>")):i.append(a('<li class="'+e+f+'"><span>'+c.html()+"</span></li>"))};j.length&&j.each(function(){if(a(this).is("option"))e?n(d,a(this),"multiple"):n(d,a(this));else if(a(this).is("optgroup")){var b=a(this).children("option");i.append(a('<li class="optgroup"><span>'+a(this).attr("label")+"</span></li>")),b.each(function(){n(d,a(this),"optgroup-option")})}}),i.find("li:not(.optgroup)").each(function(f){a(this).click(function(g){if(!a(this).hasClass("disabled")&&!a(this).hasClass("optgroup")){var h=!0;e?(a('input[type="checkbox"]',this).prop("checked",function(a,b){return!b}),h=c(k,a(this).index(),d),q.trigger("focus")):(i.find("li").removeClass("active"),a(this).toggleClass("active"),q.val(a(this).text())),r(i,a(this)),d.find("option").eq(f).prop("selected",h),d.trigger("change"),"undefined"!=typeof b&&b()}g.stopPropagation()})}),d.wrap(h);var o=a('<span class="caret">&#9660;</span>');d.is(":disabled")&&o.addClass("disabled");var p=m.replace(/"/g,"&quot;"),q=a('<input type="text" class="select-dropdown" readonly="true" '+(d.is(":disabled")?"disabled":"")+' data-activates="select-options-'+g+'" value="'+p+'"/>');d.before(q),q.before(o),q.after(i),d.is(":disabled")||q.dropdown({hover:!1,closeOnClick:!1}),d.attr("tabindex")&&a(q[0]).attr("tabindex",d.attr("tabindex")),d.addClass("initialized"),q.on({focus:function(){if(a("ul.select-dropdown").not(i[0]).is(":visible")&&a("input.select-dropdown").trigger("close"),!i.is(":visible")){a(this).trigger("open",["focus"]);var b=a(this).val();e&&b.indexOf(",")>=0&&(b=b.split(",")[0]);var c=i.find("li").filter(function(){return a(this).text().toLowerCase()===b.toLowerCase()})[0];r(i,c,!0)}},click:function(a){a.stopPropagation()}}),q.on("blur",function(){e||a(this).trigger("close"),i.find("li.selected").removeClass("selected")}),i.hover(function(){l=!0},function(){l=!1}),a(window).on({click:function(){e&&(l||q.trigger("close"))}}),e&&d.find("option:selected:not(:disabled)").each(function(){var b=a(this).index();c(k,b,d),i.find("li").eq(b).find(":checkbox").prop("checked",!0)});var r=function(b,c,d){if(c){b.find("li.selected").removeClass("selected");var f=a(c);f.addClass("selected"),e&&!d||i.scrollTo(f)}},s=[],t=function(b){if(9==b.which)return void q.trigger("close");if(40==b.which&&!i.is(":visible"))return void q.trigger("open");if(13!=b.which||i.is(":visible")){b.preventDefault();var c=String.fromCharCode(b.which).toLowerCase(),d=[9,13,27,38,40];if(c&&d.indexOf(b.which)===-1){s.push(c);var f=s.join(""),g=i.find("li").filter(function(){return 0===a(this).text().toLowerCase().indexOf(f)})[0];g&&r(i,g)}if(13==b.which){var h=i.find("li.selected:not(.disabled)")[0];h&&(a(h).trigger("click"),e||q.trigger("close"))}40==b.which&&(g=i.find("li.selected").length?i.find("li.selected").next("li:not(.disabled)")[0]:i.find("li:not(.disabled)")[0],r(i,g)),27==b.which&&q.trigger("close"),38==b.which&&(g=i.find("li.selected").prev("li:not(.disabled)")[0],g&&r(i,g)),setTimeout(function(){s=[]},1e3)}};q.on("keydown",t)}})}}(jQuery),function(a){var b={init:function(b){var c={indicators:!0,height:400,transition:500,interval:6e3};return b=a.extend(c,b),this.each(function(){function c(a,b){a.hasClass("center-align")?a.velocity({opacity:0,translateY:-100},{duration:b,queue:!1}):a.hasClass("right-align")?a.velocity({opacity:0,translateX:100},{duration:b,queue:!1}):a.hasClass("left-align")&&a.velocity({opacity:0,translateX:-100},{duration:b,queue:!1})}function d(a){a>=j.length?a=0:a<0&&(a=j.length-1),k=i.find(".active").index(),k!=a&&(e=j.eq(k),$caption=e.find(".caption"),e.removeClass("active"),e.velocity({opacity:0},{duration:b.transition,queue:!1,easing:"easeOutQuad",complete:function(){j.not(".active").velocity({opacity:0,translateX:0,translateY:0},{duration:0,queue:!1})}}),c($caption,b.transition),b.indicators&&f.eq(k).removeClass("active"),j.eq(a).velocity({opacity:1},{duration:b.transition,queue:!1,easing:"easeOutQuad"}),j.eq(a).find(".caption").velocity({opacity:1,translateX:0,translateY:0},{duration:b.transition,delay:b.transition,queue:!1,easing:"easeOutQuad"}),j.eq(a).addClass("active"),b.indicators&&f.eq(a).addClass("active"))}var e,f,g,h=a(this),i=h.find("ul.slides").first(),j=i.find("> li"),k=i.find(".active").index();k!=-1&&(e=j.eq(k)),h.hasClass("fullscreen")||(b.indicators?h.height(b.height+40):h.height(b.height),i.height(b.height)),j.find(".caption").each(function(){c(a(this),0)}),j.find("img").each(function(){var b="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";a(this).attr("src")!==b&&(a(this).css("background-image","url("+a(this).attr("src")+")"),a(this).attr("src",b))}),b.indicators&&(f=a('<ul class="indicators"></ul>'),j.each(function(c){var e=a('<li class="indicator-item"></li>');e.click(function(){var c=i.parent(),e=c.find(a(this)).index();d(e),clearInterval(g),g=setInterval(function(){k=i.find(".active").index(),j.length==k+1?k=0:k+=1,d(k)},b.transition+b.interval)}),f.append(e)}),h.append(f),f=h.find("ul.indicators").find("li.indicator-item")),e?e.show():(j.first().addClass("active").velocity({opacity:1},{duration:b.transition,queue:!1,easing:"easeOutQuad"}),k=0,e=j.eq(k),b.indicators&&f.eq(k).addClass("active")),e.find("img").each(function(){e.find(".caption").velocity({opacity:1,translateX:0,translateY:0},{duration:b.transition,queue:!1,easing:"easeOutQuad"})}),g=setInterval(function(){k=i.find(".active").index(),d(k+1)},b.transition+b.interval);var l=!1,m=!1,n=!1;h.hammer({prevent_default:!1}).bind("pan",function(a){if("touch"===a.gesture.pointerType){clearInterval(g);var b=a.gesture.direction,c=a.gesture.deltaX,d=a.gesture.velocityX,e=a.gesture.velocityY;$curr_slide=i.find(".active"),Math.abs(d)>Math.abs(e)&&$curr_slide.velocity({translateX:c},{duration:50,queue:!1,easing:"easeOutQuad"}),4===b&&(c>h.innerWidth()/2||d<-.65)?n=!0:2===b&&(c<-1*h.innerWidth()/2||d>.65)&&(m=!0);var f;m&&(f=$curr_slide.next(),0===f.length&&(f=j.first()),f.velocity({opacity:1},{duration:300,queue:!1,easing:"easeOutQuad"})),n&&(f=$curr_slide.prev(),0===f.length&&(f=j.last()),f.velocity({opacity:1},{duration:300,queue:!1,easing:"easeOutQuad"}))}}).bind("panend",function(a){"touch"===a.gesture.pointerType&&($curr_slide=i.find(".active"),l=!1,curr_index=i.find(".active").index(),!n&&!m||j.length<=1?$curr_slide.velocity({translateX:0},{duration:300,queue:!1,easing:"easeOutQuad"}):m?(d(curr_index+1),$curr_slide.velocity({translateX:-1*h.innerWidth()},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){$curr_slide.velocity({opacity:0,translateX:0},{duration:0,queue:!1})}})):n&&(d(curr_index-1),$curr_slide.velocity({translateX:h.innerWidth()},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){$curr_slide.velocity({opacity:0,translateX:0},{duration:0,queue:!1})}})),m=!1,n=!1,clearInterval(g),g=setInterval(function(){k=i.find(".active").index(),j.length==k+1?k=0:k+=1,d(k)},b.transition+b.interval))}),h.on("sliderPause",function(){clearInterval(g)}),h.on("sliderStart",function(){clearInterval(g),g=setInterval(function(){k=i.find(".active").index(),j.length==k+1?k=0:k+=1,d(k)},b.transition+b.interval)}),h.on("sliderNext",function(){k=i.find(".active").index(),d(k+1)}),h.on("sliderPrev",function(){k=i.find(".active").index(),d(k-1)})})},pause:function(){a(this).trigger("sliderPause")},start:function(){a(this).trigger("sliderStart")},next:function(){a(this).trigger("sliderNext")},prev:function(){a(this).trigger("sliderPrev")}};a.fn.slider=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.tooltip"):b.init.apply(this,arguments)}}(jQuery),function(a){a(document).ready(function(){a(document).on("click.card",".card",function(b){a(this).find("> .card-reveal").length&&(a(b.target).is(a(".card-reveal .card-title"))||a(b.target).is(a(".card-reveal .card-title i"))?a(this).find(".card-reveal").velocity({translateY:0},{duration:225,queue:!1,easing:"easeInOutQuad",complete:function(){a(this).css({display:"none"})}}):(a(b.target).is(a(".card .activator"))||a(b.target).is(a(".card .activator i")))&&(a(b.target).closest(".card").css("overflow","hidden"),a(this).find(".card-reveal").css({display:"block"}).velocity("stop",!1).velocity({translateY:"-100%"},{duration:300,queue:!1,easing:"easeInOutQuad"})))})})}(jQuery),function(a){var b={data:[],placeholder:"",secondaryPlaceholder:"",autocompleteData:{},autocompleteLimit:1/0};a(document).ready(function(){a(document).on("click",".chip .close",function(b){var c=a(this).closest(".chips");c.attr("data-initialized")||a(this).closest(".chip").remove()})}),a.fn.material_chip=function(c){var d=this;if(this.$el=a(this),this.$document=a(document),this.SELS={CHIPS:".chips",CHIP:".chip",INPUT:"input",DELETE:".material-icons",SELECTED_CHIP:".selected"},"data"===c)return this.$el.data("chips");var e=a.extend({},b,c);d.hasAutocomplete=!a.isEmptyObject(e.autocompleteData),this.init=function(){var b=0;d.$el.each(function(){var c=a(this),f=Materialize.guid();d.chipId=f,e.data&&e.data instanceof Array||(e.data=[]),c.data("chips",e.data),c.attr("data-index",b),c.attr("data-initialized",!0),c.hasClass(d.SELS.CHIPS)||c.addClass("chips"),d.chips(c,f),b++})},this.handleEvents=function(){var b=d.SELS;d.$document.off("click.chips-focus",b.CHIPS).on("click.chips-focus",b.CHIPS,function(c){a(c.target).find(b.INPUT).focus()}),d.$document.off("click.chips-select",b.CHIP).on("click.chips-select",b.CHIP,function(c){var e=a(c.target);if(e.length){var f=e.hasClass("selected"),g=e.closest(b.CHIPS);a(b.CHIP).removeClass("selected"),f||d.selectChip(e.index(),g)}}),d.$document.off("keydown.chips").on("keydown.chips",function(c){if(!a(c.target).is("input, textarea")){var e,f=d.$document.find(b.CHIP+b.SELECTED_CHIP),g=f.closest(b.CHIPS),h=f.siblings(b.CHIP).length;if(f.length)if(8===c.which||46===c.which){c.preventDefault(),e=f.index(),d.deleteChip(e,g);var i=null;e+1<h?i=e:e!==h&&e+1!==h||(i=h-1),i<0&&(i=null),null!==i&&d.selectChip(i,g),h||g.find("input").focus()}else if(37===c.which){if(e=f.index()-1,e<0)return;a(b.CHIP).removeClass("selected"),d.selectChip(e,g)}else if(39===c.which){if(e=f.index()+1,a(b.CHIP).removeClass("selected"),e>h)return void g.find("input").focus();d.selectChip(e,g)}}}),d.$document.off("focusin.chips",b.CHIPS+" "+b.INPUT).on("focusin.chips",b.CHIPS+" "+b.INPUT,function(c){var d=a(c.target).closest(b.CHIPS);d.addClass("focus"),d.siblings("label, .prefix").addClass("active"),a(b.CHIP).removeClass("selected")}),d.$document.off("focusout.chips",b.CHIPS+" "+b.INPUT).on("focusout.chips",b.CHIPS+" "+b.INPUT,function(c){var d=a(c.target).closest(b.CHIPS);d.removeClass("focus"),d.data("chips").length||d.siblings("label").removeClass("active"),d.siblings(".prefix").removeClass("active")}),d.$document.off("keydown.chips-add",b.CHIPS+" "+b.INPUT).on("keydown.chips-add",b.CHIPS+" "+b.INPUT,function(c){var e=a(c.target),f=e.closest(b.CHIPS),g=f.children(b.CHIP).length;if(13===c.which){if(d.hasAutocomplete&&f.find(".autocomplete-content.dropdown-content").length&&f.find(".autocomplete-content.dropdown-content").children().length)return;return c.preventDefault(),d.addChip({tag:e.val()},f),void e.val("")}if((8===c.keyCode||37===c.keyCode)&&""===e.val()&&g)return c.preventDefault(),d.selectChip(g-1,f),void e.blur()}),d.$document.off("click.chips-delete",b.CHIPS+" "+b.DELETE).on("click.chips-delete",b.CHIPS+" "+b.DELETE,function(c){var e=a(c.target),f=e.closest(b.CHIPS),g=e.closest(b.CHIP);c.stopPropagation(),d.deleteChip(g.index(),f),f.find("input").focus()})},this.chips=function(b,c){var f="";b.data("chips").forEach(function(a){f+=d.renderChip(a)}),f+='<input id="'+c+'" class="input" placeholder="">',b.html(f),d.setPlaceholder(b);var g=b.next("label");g.length&&(g.attr("for",c),b.data("chips").length&&g.addClass("active"));var h=a("#"+c);d.hasAutocomplete&&h.autocomplete({data:e.autocompleteData,limit:e.autocompleteLimit,onAutocomplete:function(a){d.addChip({tag:a},b),h.val(""),h.focus()}})},this.renderChip=function(a){if(a.tag){var b='<div class="chip">'+a.tag;return a.image&&(b+=' <img src="'+a.image+'"> '),b+='<i class="material-icons close">close</i>',b+="</div>"}},this.setPlaceholder=function(a){a.data("chips").length&&e.placeholder?a.find("input").prop("placeholder",e.placeholder):!a.data("chips").length&&e.secondaryPlaceholder&&a.find("input").prop("placeholder",e.secondaryPlaceholder)},this.isValid=function(a,b){for(var c=a.data("chips"),d=!1,e=0;e<c.length;e++)if(c[e].tag===b.tag)return void(d=!0);return""!==b.tag&&!d},this.addChip=function(b,c){if(d.isValid(c,b)){for(var e=d.renderChip(b),f=[],g=c.data("chips"),h=0;h<g.length;h++)f.push(g[h]);f.push(b),c.data("chips",f),a(e).insertBefore(c.find("input")),c.trigger("chip.add",b),d.setPlaceholder(c)}},this.deleteChip=function(a,b){var c=b.data("chips")[a];b.find(".chip").eq(a).remove();for(var e=[],f=b.data("chips"),g=0;g<f.length;g++)g!==a&&e.push(f[g]);b.data("chips",e),b.trigger("chip.delete",c),d.setPlaceholder(b)},this.selectChip=function(a,b){var c=b.find(".chip").eq(a);c&&!1===c.hasClass("selected")&&(c.addClass("selected"),b.trigger("chip.select",b.data("chips")[a]))},this.getChipsElement=function(a,b){return b.eq(a)},this.init(),this.handleEvents()}}(jQuery),function(a){a.fn.pushpin=function(b){var c={top:0,bottom:1/0,offset:0};return"remove"===b?(this.each(function(){(id=a(this).data("pushpin-id"))&&(a(window).off("scroll."+id),a(this).removeData("pushpin-id").removeClass("pin-top pinned pin-bottom").removeAttr("style"))}),!1):(b=a.extend(c,b),$index=0,this.each(function(){function c(a){a.removeClass("pin-top"),a.removeClass("pinned"),a.removeClass("pin-bottom")}function d(d,e){d.each(function(){b.top<=e&&b.bottom>=e&&!a(this).hasClass("pinned")&&(c(a(this)),a(this).css("top",b.offset),a(this).addClass("pinned")),e<b.top&&!a(this).hasClass("pin-top")&&(c(a(this)),a(this).css("top",0),a(this).addClass("pin-top")),e>b.bottom&&!a(this).hasClass("pin-bottom")&&(c(a(this)),a(this).addClass("pin-bottom"),a(this).css("top",b.bottom-g))})}var e=Materialize.guid(),f=a(this),g=a(this).offset().top;a(this).data("pushpin-id",e),d(f,a(window).scrollTop()),a(window).on("scroll."+e,function(){var c=a(window).scrollTop()+b.offset;d(f,c)})}))}}(jQuery),function(a){a(document).ready(function(){a.fn.reverse=[].reverse,a(document).on("mouseenter.fixedActionBtn",".fixed-action-btn:not(.click-to-toggle):not(.toolbar)",function(c){var d=a(this);b(d)}),a(document).on("mouseleave.fixedActionBtn",".fixed-action-btn:not(.click-to-toggle):not(.toolbar)",function(b){var d=a(this);c(d)}),a(document).on("click.fabClickToggle",".fixed-action-btn.click-to-toggle > a",function(d){var e=a(this),f=e.parent();f.hasClass("active")?c(f):b(f)}),a(document).on("click.fabToolbar",".fixed-action-btn.toolbar > a",function(b){var c=a(this),e=c.parent();d(e)})}),a.fn.extend({openFAB:function(){b(a(this))},closeFAB:function(){c(a(this))},openToolbar:function(){d(a(this))},closeToolbar:function(){e(a(this))}});var b=function(b){var c=b;if(c.hasClass("active")===!1){var d,e,f=c.hasClass("horizontal");f===!0?e=40:d=40,c.addClass("active"),c.find("ul .btn-floating").velocity({scaleY:".4",scaleX:".4",translateY:d+"px",translateX:e+"px"},{duration:0});var g=0;c.find("ul .btn-floating").reverse().each(function(){a(this).velocity({opacity:"1",scaleX:"1",scaleY:"1",translateY:"0",translateX:"0"},{duration:80,delay:g}),g+=40})}},c=function(a){var b,c,d=a,e=d.hasClass("horizontal");e===!0?c=40:b=40,d.removeClass("active");d.find("ul .btn-floating").velocity("stop",!0),d.find("ul .btn-floating").velocity({opacity:"0",scaleX:".4",scaleY:".4",translateY:b+"px",translateX:c+"px"},{duration:80})},d=function(b){if("true"!==b.attr("data-open")){var c,d,f,g=window.innerWidth,h=window.innerHeight,i=b[0].getBoundingClientRect(),j=b.find("> a").first(),k=b.find("> ul").first(),l=a('<div class="fab-backdrop"></div>'),m=j.css("background-color");j.append(l),c=i.left-g/2+i.width/2,d=h-i.bottom,f=g/l.width(),b.attr("data-origin-bottom",i.bottom),b.attr("data-origin-left",i.left),b.attr("data-origin-width",i.width),b.addClass("active"),b.attr("data-open",!0),b.css({"text-align":"center",width:"100%",bottom:0,left:0,transform:"translateX("+c+"px)",transition:"none"}),j.css({transform:"translateY("+-d+"px)",transition:"none"}),l.css({"background-color":m}),setTimeout(function(){b.css({transform:"",transition:"transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s"}),j.css({overflow:"visible",transform:"",transition:"transform .2s"}),setTimeout(function(){b.css({overflow:"hidden","background-color":m}),l.css({transform:"scale("+f+")",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"}),k.find("> li > a").css({opacity:1}),a(window).on("scroll.fabToolbarClose",function(){e(b),a(window).off("scroll.fabToolbarClose"),a(document).off("click.fabToolbarClose")}),a(document).on("click.fabToolbarClose",function(c){a(c.target).closest(k).length||(e(b),a(window).off("scroll.fabToolbarClose"),a(document).off("click.fabToolbarClose"))})},100)},0)}},e=function(a){if("true"===a.attr("data-open")){var b,c,d,e=window.innerWidth,f=window.innerHeight,g=a.attr("data-origin-width"),h=a.attr("data-origin-bottom"),i=a.attr("data-origin-left"),j=a.find("> .btn-floating").first(),k=a.find("> ul").first(),l=a.find(".fab-backdrop"),m=j.css("background-color");b=i-e/2+g/2,c=f-h,d=e/l.width(),a.removeClass("active"),a.attr("data-open",!1),a.css({"background-color":"transparent",transition:"none"}),j.css({transition:"none"}),l.css({transform:"scale(0)","background-color":m}),k.find("> li > a").css({opacity:""}),setTimeout(function(){l.remove(),a.css({"text-align":"",width:"",bottom:"",left:"",overflow:"","background-color":"",transform:"translate3d("+-b+"px,0,0)"}),j.css({overflow:"",transform:"translate3d(0,"+c+"px,0)"}),setTimeout(function(){a.css({transform:"translate3d(0,0,0)",transition:"transform .2s"}),j.css({transform:"translate3d(0,0,0)",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"})},20)},200)}}}(jQuery),function(a){Materialize.fadeInImage=function(b){var c;if("string"==typeof b)c=a(b);else{if("object"!=typeof b)return;c=b}c.css({opacity:0}),a(c).velocity({opacity:1},{duration:650,queue:!1,easing:"easeOutSine"}),a(c).velocity({opacity:1},{duration:1300,queue:!1,easing:"swing",step:function(b,c){c.start=100;var d=b/100,e=150-(100-b)/1.75;e<100&&(e=100),b>=0&&a(this).css({"-webkit-filter":"grayscale("+d+")brightness("+e+"%)",filter:"grayscale("+d+")brightness("+e+"%)"})}})},Materialize.showStaggeredList=function(b){var c;if("string"==typeof b)c=a(b);else{if("object"!=typeof b)return;c=b}var d=0;c.find("li").velocity({translateX:"-100px"},{duration:0}),c.find("li").each(function(){a(this).velocity({opacity:"1",translateX:"0"},{duration:800,delay:d,easing:[60,10]}),d+=120})},a(document).ready(function(){var b=!1,c=!1;a(".dismissable").each(function(){a(this).hammer({prevent_default:!1}).bind("pan",function(d){if("touch"===d.gesture.pointerType){var e=a(this),f=d.gesture.direction,g=d.gesture.deltaX,h=d.gesture.velocityX;e.velocity({translateX:g},{duration:50,queue:!1,easing:"easeOutQuad"}),4===f&&(g>e.innerWidth()/2||h<-.75)&&(b=!0),2===f&&(g<-1*e.innerWidth()/2||h>.75)&&(c=!0)}}).bind("panend",function(d){if(Math.abs(d.gesture.deltaX)<a(this).innerWidth()/2&&(c=!1,b=!1),"touch"===d.gesture.pointerType){var e=a(this);if(b||c){var f;f=b?e.innerWidth():-1*e.innerWidth(),e.velocity({translateX:f},{duration:100,queue:!1,easing:"easeOutQuad",complete:function(){e.css("border","none"),e.velocity({height:0,padding:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){e.remove()}})}})}else e.velocity({translateX:0},{duration:100,queue:!1,easing:"easeOutQuad"});b=!1,c=!1}})})})}(jQuery),function(a){var b=!1;Materialize.scrollFire=function(a){var c=function(){for(var b=window.pageYOffset+window.innerHeight,c=0;c<a.length;c++){var d=a[c],e=d.selector,f=d.offset,g=d.callback,h=document.querySelector(e);if(null!==h){var i=h.getBoundingClientRect().top+window.pageYOffset;if(b>i+f&&d.done!==!0){if("function"==typeof g)g.call(this,h);else if("string"==typeof g){var j=new Function(g);j(h)}d.done=!0}}}},d=Materialize.throttle(function(){c()},a.throttle||100);b||(window.addEventListener("scroll",d),window.addEventListener("resize",d),b=!0),setTimeout(d,0)}}(jQuery),function(a){"function"==typeof define&&define.amd?define("picker",["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):this.Picker=a(jQuery)}(function(a){function b(f,g,i,l){function m(){return b._.node("div",b._.node("div",b._.node("div",b._.node("div",y.component.nodes(t.open),v.box),v.wrap),v.frame),v.holder)}function n(){w.data(g,y).addClass(v.input).attr("tabindex",-1).val(w.data("value")?y.get("select",u.format):f.value),u.editable||w.on("focus."+t.id+" click."+t.id,function(a){a.preventDefault(),y.$root.eq(0).focus()}).on("keydown."+t.id,q),e(f,{haspopup:!0,expanded:!1,readonly:!1,owns:f.id+"_root"})}function o(){y.$root.on({keydown:q,focusin:function(a){y.$root.removeClass(v.focused),a.stopPropagation()},"mousedown click":function(b){var c=b.target;c!=y.$root.children()[0]&&(b.stopPropagation(),"mousedown"!=b.type||a(c).is("input, select, textarea, button, option")||(b.preventDefault(),y.$root.eq(0).focus()))}}).on({focus:function(){w.addClass(v.target)},blur:function(){w.removeClass(v.target)}}).on("focus.toOpen",r).on("click","[data-pick], [data-nav], [data-clear], [data-close]",function(){var b=a(this),c=b.data(),d=b.hasClass(v.navDisabled)||b.hasClass(v.disabled),e=h();e=e&&(e.type||e.href),(d||e&&!a.contains(y.$root[0],e))&&y.$root.eq(0).focus(),!d&&c.nav?y.set("highlight",y.component.item.highlight,{nav:c.nav}):!d&&"pick"in c?y.set("select",c.pick):c.clear?y.clear().close(!0):c.close&&y.close(!0)}),e(y.$root[0],"hidden",!0)}function p(){var b;u.hiddenName===!0?(b=f.name,f.name=""):(b=["string"==typeof u.hiddenPrefix?u.hiddenPrefix:"","string"==typeof u.hiddenSuffix?u.hiddenSuffix:"_submit"],b=b[0]+f.name+b[1]),y._hidden=a('<input type=hidden name="'+b+'"'+(w.data("value")||f.value?' value="'+y.get("select",u.formatSubmit)+'"':"")+">")[0],w.on("change."+t.id,function(){y._hidden.value=f.value?y.get("select",u.formatSubmit):""}),u.container?a(u.container).append(y._hidden):w.after(y._hidden)}function q(a){var b=a.keyCode,c=/^(8|46)$/.test(b);return 27==b?(y.close(),!1):void((32==b||c||!t.open&&y.component.key[b])&&(a.preventDefault(),a.stopPropagation(),c?y.clear().close():y.open()))}function r(a){a.stopPropagation(),"focus"==a.type&&y.$root.addClass(v.focused),y.open()}if(!f)return b;var s=!1,t={id:f.id||"P"+Math.abs(~~(Math.random()*new Date))},u=i?a.extend(!0,{},i.defaults,l):l||{},v=a.extend({},b.klasses(),u.klass),w=a(f),x=function(){return this.start()},y=x.prototype={constructor:x,$node:w,start:function(){return t&&t.start?y:(t.methods={},t.start=!0,t.open=!1,t.type=f.type,f.autofocus=f==h(),f.readOnly=!u.editable,f.id=f.id||t.id,"text"!=f.type&&(f.type="text"),y.component=new i(y,u),y.$root=a(b._.node("div",m(),v.picker,'id="'+f.id+'_root" tabindex="0"')),o(),u.formatSubmit&&p(),n(),u.container?a(u.container).append(y.$root):w.after(y.$root),y.on({start:y.component.onStart,render:y.component.onRender,stop:y.component.onStop,open:y.component.onOpen,close:y.component.onClose,set:y.component.onSet}).on({start:u.onStart,render:u.onRender,stop:u.onStop,open:u.onOpen,close:u.onClose,set:u.onSet}),s=c(y.$root.children()[0]),f.autofocus&&y.open(),y.trigger("start").trigger("render"))},render:function(a){return a?y.$root.html(m()):y.$root.find("."+v.box).html(y.component.nodes(t.open)),y.trigger("render")},stop:function(){return t.start?(y.close(),y._hidden&&y._hidden.parentNode.removeChild(y._hidden),y.$root.remove(),w.removeClass(v.input).removeData(g),setTimeout(function(){w.off("."+t.id)},0),f.type=t.type,f.readOnly=!1,y.trigger("stop"),t.methods={},t.start=!1,y):y},open:function(c){return t.open?y:(w.addClass(v.active),e(f,"expanded",!0),setTimeout(function(){y.$root.addClass(v.opened),e(y.$root[0],"hidden",!1)},0),c!==!1&&(t.open=!0,s&&k.css("overflow","hidden").css("padding-right","+="+d()),y.$root.eq(0).focus(),j.on("click."+t.id+" focusin."+t.id,function(a){var b=a.target;b!=f&&b!=document&&3!=a.which&&y.close(b===y.$root.children()[0])}).on("keydown."+t.id,function(c){var d=c.keyCode,e=y.component.key[d],f=c.target;27==d?y.close(!0):f!=y.$root[0]||!e&&13!=d?a.contains(y.$root[0],f)&&13==d&&(c.preventDefault(),f.click()):(c.preventDefault(),e?b._.trigger(y.component.key.go,y,[b._.trigger(e)]):y.$root.find("."+v.highlighted).hasClass(v.disabled)||y.set("select",y.component.item.highlight).close())})),y.trigger("open"))},close:function(a){return a&&(y.$root.off("focus.toOpen").eq(0).focus(),setTimeout(function(){y.$root.on("focus.toOpen",r)},0)),w.removeClass(v.active),e(f,"expanded",!1),setTimeout(function(){y.$root.removeClass(v.opened+" "+v.focused),e(y.$root[0],"hidden",!0)},0),t.open?(t.open=!1,s&&k.css("overflow","").css("padding-right","-="+d()),j.off("."+t.id),y.trigger("close")):y},clear:function(a){return y.set("clear",null,a)},set:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(d=g&&a.isPlainObject(c)?c:d||{},b){g||(h[b]=c);for(e in h)f=h[e],e in y.component.item&&(void 0===f&&(f=null),y.component.set(e,f,d)),"select"!=e&&"clear"!=e||w.val("clear"==e?"":y.get(e,u.format)).trigger("change");y.render()}return d.muted?y:y.trigger("set",h)},get:function(a,c){if(a=a||"value",null!=t[a])return t[a];if("valueSubmit"==a){if(y._hidden)return y._hidden.value;a="value"}if("value"==a)return f.value;if(a in y.component.item){if("string"==typeof c){var d=y.component.get(a);return d?b._.trigger(y.component.formats.toString,y.component,[c,d]):""}return y.component.get(a)}},on:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(b){g||(h[b]=c);for(e in h)f=h[e],d&&(e="_"+e),t.methods[e]=t.methods[e]||[],t.methods[e].push(f)}return y},off:function(){var a,b,c=arguments;for(a=0,namesCount=c.length;a<namesCount;a+=1)b=c[a],b in t.methods&&delete t.methods[b];return y},trigger:function(a,c){var d=function(a){var d=t.methods[a];d&&d.map(function(a){b._.trigger(a,y,[c])})};return d("_"+a),d(a),y}};return new x}function c(a){var b,c="position";return a.currentStyle?b=a.currentStyle[c]:window.getComputedStyle&&(b=getComputedStyle(a)[c]),"fixed"==b}function d(){if(k.height()<=i.height())return 0;var b=a('<div style="visibility:hidden;width:100px" />').appendTo("body"),c=b[0].offsetWidth;b.css("overflow","scroll");var d=a('<div style="width:100%" />').appendTo(b),e=d[0].offsetWidth;return b.remove(),c-e}function e(b,c,d){if(a.isPlainObject(c))for(var e in c)f(b,e,c[e]);else f(b,c,d)}function f(a,b,c){a.setAttribute(("role"==b?"":"aria-")+b,c)}function g(b,c){a.isPlainObject(b)||(b={attribute:c}),c="";for(var d in b){var e=("role"==d?"":"aria-")+d,f=b[d];c+=null==f?"":e+'="'+b[d]+'"'}return c}function h(){try{return document.activeElement}catch(a){}}var i=a(window),j=a(document),k=a(document.documentElement);return b.klasses=function(a){return a=a||"picker",{picker:a,opened:a+"--opened",focused:a+"--focused",input:a+"__input",active:a+"__input--active",target:a+"__input--target",holder:a+"__holder",frame:a+"__frame",wrap:a+"__wrap",box:a+"__box"}},b._={group:function(a){for(var c,d="",e=b._.trigger(a.min,a);e<=b._.trigger(a.max,a,[e]);e+=a.i)c=b._.trigger(a.item,a,[e]),d+=b._.node(a.node,c[0],c[1],c[2]);return d},node:function(b,c,d,e){return c?(c=a.isArray(c)?c.join(""):c,d=d?' class="'+d+'"':"",e=e?" "+e:"","<"+b+d+e+">"+c+"</"+b+">"):""},lead:function(a){return(a<10?"0":"")+a},trigger:function(a,b,c){return"function"==typeof a?a.apply(b,c||[]):a},digits:function(a){return/\d/.test(a[1])?2:1},isDate:function(a){return{}.toString.call(a).indexOf("Date")>-1&&this.isInteger(a.getDate())},isInteger:function(a){return{}.toString.call(a).indexOf("Number")>-1&&a%1===0},ariaAttr:g},b.extend=function(c,d){a.fn[c]=function(e,f){var g=this.data(c);return"picker"==e?g:g&&"string"==typeof e?b._.trigger(g[e],g,[f]):this.each(function(){var f=a(this);f.data(c)||new b(this,c,d,e)})},a.fn[c].defaults=d.defaults},b}),function(a){"function"==typeof define&&define.amd?define(["picker","jquery"],a):"object"==typeof exports?module.exports=a(require("./picker.js"),require("jquery")):a(Picker,jQuery)}(function(a,b){function c(a,b){var c=this,d=a.$node[0],e=d.value,f=a.$node.data("value"),g=f||e,h=f?b.formatSubmit:b.format,i=function(){return d.currentStyle?"rtl"==d.currentStyle.direction:"rtl"==getComputedStyle(a.$root[0]).direction};c.settings=b,c.$node=a.$node,c.queue={min:"measure create",max:"measure create",now:"now create",select:"parse create validate",highlight:"parse navigate create validate",view:"parse create validate viewset",disable:"deactivate",enable:"activate"},c.item={},c.item.clear=null,c.item.disable=(b.disable||[]).slice(0),c.item.enable=-function(a){return a[0]===!0?a.shift():-1}(c.item.disable),c.set("min",b.min).set("max",b.max).set("now"),g?c.set("select",g,{format:h}):c.set("select",null).set("highlight",c.item.now),c.key={40:7,38:-7,39:function(){return i()?-1:1},37:function(){return i()?1:-1},go:function(a){var b=c.item.highlight,d=new Date(b.year,b.month,b.date+a);c.set("highlight",d,{interval:a}),this.render()}},a.on("render",function(){a.$root.find("."+b.klass.selectMonth).on("change",function(){var c=this.value;c&&(a.set("highlight",[a.get("view").year,c,a.get("highlight").date]),a.$root.find("."+b.klass.selectMonth).trigger("focus"))}),a.$root.find("."+b.klass.selectYear).on("change",function(){var c=this.value;c&&(a.set("highlight",[c,a.get("view").month,a.get("highlight").date]),a.$root.find("."+b.klass.selectYear).trigger("focus"))})},1).on("open",function(){var d="";c.disabled(c.get("now"))&&(d=":not(."+b.klass.buttonToday+")"),a.$root.find("button"+d+", select").attr("disabled",!1)},1).on("close",function(){a.$root.find("button, select").attr("disabled",!0)},1)}var d=7,e=6,f=a._;c.prototype.set=function(a,b,c){var d=this,e=d.item;return null===b?("clear"==a&&(a="select"),e[a]=b,d):(e["enable"==a?"disable":"flip"==a?"enable":a]=d.queue[a].split(" ").map(function(e){return b=d[e](a,b,c)}).pop(),"select"==a?d.set("highlight",e.select,c):"highlight"==a?d.set("view",e.highlight,c):a.match(/^(flip|min|max|disable|enable)$/)&&(e.select&&d.disabled(e.select)&&d.set("select",e.select,c),e.highlight&&d.disabled(e.highlight)&&d.set("highlight",e.highlight,c)),d)},c.prototype.get=function(a){return this.item[a]},c.prototype.create=function(a,c,d){var e,g=this;return c=void 0===c?a:c,
-c==-(1/0)||c==1/0?e=c:b.isPlainObject(c)&&f.isInteger(c.pick)?c=c.obj:b.isArray(c)?(c=new Date(c[0],c[1],c[2]),c=f.isDate(c)?c:g.create().obj):c=f.isInteger(c)||f.isDate(c)?g.normalize(new Date(c),d):g.now(a,c,d),{year:e||c.getFullYear(),month:e||c.getMonth(),date:e||c.getDate(),day:e||c.getDay(),obj:e||c,pick:e||c.getTime()}},c.prototype.createRange=function(a,c){var d=this,e=function(a){return a===!0||b.isArray(a)||f.isDate(a)?d.create(a):a};return f.isInteger(a)||(a=e(a)),f.isInteger(c)||(c=e(c)),f.isInteger(a)&&b.isPlainObject(c)?a=[c.year,c.month,c.date+a]:f.isInteger(c)&&b.isPlainObject(a)&&(c=[a.year,a.month,a.date+c]),{from:e(a),to:e(c)}},c.prototype.withinRange=function(a,b){return a=this.createRange(a.from,a.to),b.pick>=a.from.pick&&b.pick<=a.to.pick},c.prototype.overlapRanges=function(a,b){var c=this;return a=c.createRange(a.from,a.to),b=c.createRange(b.from,b.to),c.withinRange(a,b.from)||c.withinRange(a,b.to)||c.withinRange(b,a.from)||c.withinRange(b,a.to)},c.prototype.now=function(a,b,c){return b=new Date,c&&c.rel&&b.setDate(b.getDate()+c.rel),this.normalize(b,c)},c.prototype.navigate=function(a,c,d){var e,f,g,h,i=b.isArray(c),j=b.isPlainObject(c),k=this.item.view;if(i||j){for(j?(f=c.year,g=c.month,h=c.date):(f=+c[0],g=+c[1],h=+c[2]),d&&d.nav&&k&&k.month!==g&&(f=k.year,g=k.month),e=new Date(f,g+(d&&d.nav?d.nav:0),1),f=e.getFullYear(),g=e.getMonth();new Date(f,g,h).getMonth()!==g;)h-=1;c=[f,g,h]}return c},c.prototype.normalize=function(a){return a.setHours(0,0,0,0),a},c.prototype.measure=function(a,b){var c=this;return b?"string"==typeof b?b=c.parse(a,b):f.isInteger(b)&&(b=c.now(a,b,{rel:b})):b="min"==a?-(1/0):1/0,b},c.prototype.viewset=function(a,b){return this.create([b.year,b.month,1])},c.prototype.validate=function(a,c,d){var e,g,h,i,j=this,k=c,l=d&&d.interval?d.interval:1,m=j.item.enable===-1,n=j.item.min,o=j.item.max,p=m&&j.item.disable.filter(function(a){if(b.isArray(a)){var d=j.create(a).pick;d<c.pick?e=!0:d>c.pick&&(g=!0)}return f.isInteger(a)}).length;if((!d||!d.nav)&&(!m&&j.disabled(c)||m&&j.disabled(c)&&(p||e||g)||!m&&(c.pick<=n.pick||c.pick>=o.pick)))for(m&&!p&&(!g&&l>0||!e&&l<0)&&(l*=-1);j.disabled(c)&&(Math.abs(l)>1&&(c.month<k.month||c.month>k.month)&&(c=k,l=l>0?1:-1),c.pick<=n.pick?(h=!0,l=1,c=j.create([n.year,n.month,n.date+(c.pick===n.pick?0:-1)])):c.pick>=o.pick&&(i=!0,l=-1,c=j.create([o.year,o.month,o.date+(c.pick===o.pick?0:1)])),!h||!i);)c=j.create([c.year,c.month,c.date+l]);return c},c.prototype.disabled=function(a){var c=this,d=c.item.disable.filter(function(d){return f.isInteger(d)?a.day===(c.settings.firstDay?d:d-1)%7:b.isArray(d)||f.isDate(d)?a.pick===c.create(d).pick:b.isPlainObject(d)?c.withinRange(d,a):void 0});return d=d.length&&!d.filter(function(a){return b.isArray(a)&&"inverted"==a[3]||b.isPlainObject(a)&&a.inverted}).length,c.item.enable===-1?!d:d||a.pick<c.item.min.pick||a.pick>c.item.max.pick},c.prototype.parse=function(a,b,c){var d=this,e={};return b&&"string"==typeof b?(c&&c.format||(c=c||{},c.format=d.settings.format),d.formats.toArray(c.format).map(function(a){var c=d.formats[a],g=c?f.trigger(c,d,[b,e]):a.replace(/^!/,"").length;c&&(e[a]=b.substr(0,g)),b=b.substr(g)}),[e.yyyy||e.yy,+(e.mm||e.m)-1,e.dd||e.d]):b},c.prototype.formats=function(){function a(a,b,c){var d=a.match(/\w+/)[0];return c.mm||c.m||(c.m=b.indexOf(d)+1),d.length}function b(a){return a.match(/\w+/)[0].length}return{d:function(a,b){return a?f.digits(a):b.date},dd:function(a,b){return a?2:f.lead(b.date)},ddd:function(a,c){return a?b(a):this.settings.weekdaysShort[c.day]},dddd:function(a,c){return a?b(a):this.settings.weekdaysFull[c.day]},m:function(a,b){return a?f.digits(a):b.month+1},mm:function(a,b){return a?2:f.lead(b.month+1)},mmm:function(b,c){var d=this.settings.monthsShort;return b?a(b,d,c):d[c.month]},mmmm:function(b,c){var d=this.settings.monthsFull;return b?a(b,d,c):d[c.month]},yy:function(a,b){return a?2:(""+b.year).slice(2)},yyyy:function(a,b){return a?4:b.year},toArray:function(a){return a.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g)},toString:function(a,b){var c=this;return c.formats.toArray(a).map(function(a){return f.trigger(c.formats[a],c,[0,b])||a.replace(/^!/,"")}).join("")}}}(),c.prototype.isDateExact=function(a,c){var d=this;return f.isInteger(a)&&f.isInteger(c)||"boolean"==typeof a&&"boolean"==typeof c?a===c:(f.isDate(a)||b.isArray(a))&&(f.isDate(c)||b.isArray(c))?d.create(a).pick===d.create(c).pick:!(!b.isPlainObject(a)||!b.isPlainObject(c))&&(d.isDateExact(a.from,c.from)&&d.isDateExact(a.to,c.to))},c.prototype.isDateOverlap=function(a,c){var d=this,e=d.settings.firstDay?1:0;return f.isInteger(a)&&(f.isDate(c)||b.isArray(c))?(a=a%7+e,a===d.create(c).day+1):f.isInteger(c)&&(f.isDate(a)||b.isArray(a))?(c=c%7+e,c===d.create(a).day+1):!(!b.isPlainObject(a)||!b.isPlainObject(c))&&d.overlapRanges(a,c)},c.prototype.flipEnable=function(a){var b=this.item;b.enable=a||(b.enable==-1?1:-1)},c.prototype.deactivate=function(a,c){var d=this,e=d.item.disable.slice(0);return"flip"==c?d.flipEnable():c===!1?(d.flipEnable(1),e=[]):c===!0?(d.flipEnable(-1),e=[]):c.map(function(a){for(var c,g=0;g<e.length;g+=1)if(d.isDateExact(a,e[g])){c=!0;break}c||(f.isInteger(a)||f.isDate(a)||b.isArray(a)||b.isPlainObject(a)&&a.from&&a.to)&&e.push(a)}),e},c.prototype.activate=function(a,c){var d=this,e=d.item.disable,g=e.length;return"flip"==c?d.flipEnable():c===!0?(d.flipEnable(1),e=[]):c===!1?(d.flipEnable(-1),e=[]):c.map(function(a){var c,h,i,j;for(i=0;i<g;i+=1){if(h=e[i],d.isDateExact(h,a)){c=e[i]=null,j=!0;break}if(d.isDateOverlap(h,a)){b.isPlainObject(a)?(a.inverted=!0,c=a):b.isArray(a)?(c=a,c[3]||c.push("inverted")):f.isDate(a)&&(c=[a.getFullYear(),a.getMonth(),a.getDate(),"inverted"]);break}}if(c)for(i=0;i<g;i+=1)if(d.isDateExact(e[i],a)){e[i]=null;break}if(j)for(i=0;i<g;i+=1)if(d.isDateOverlap(e[i],a)){e[i]=null;break}c&&e.push(c)}),e.filter(function(a){return null!=a})},c.prototype.nodes=function(a){var b=this,c=b.settings,g=b.item,h=g.now,i=g.select,j=g.highlight,k=g.view,l=g.disable,m=g.min,n=g.max,o=function(a,b){return c.firstDay&&(a.push(a.shift()),b.push(b.shift())),f.node("thead",f.node("tr",f.group({min:0,max:d-1,i:1,node:"th",item:function(d){return[a[d],c.klass.weekdays,'scope=col title="'+b[d]+'"']}})))}((c.showWeekdaysFull?c.weekdaysFull:c.weekdaysLetter).slice(0),c.weekdaysFull.slice(0)),p=function(a){return f.node("div"," ",c.klass["nav"+(a?"Next":"Prev")]+(a&&k.year>=n.year&&k.month>=n.month||!a&&k.year<=m.year&&k.month<=m.month?" "+c.klass.navDisabled:""),"data-nav="+(a||-1)+" "+f.ariaAttr({role:"button",controls:b.$node[0].id+"_table"})+' title="'+(a?c.labelMonthNext:c.labelMonthPrev)+'"')},q=function(d){var e=c.showMonthsShort?c.monthsShort:c.monthsFull;return"short_months"==d&&(e=c.monthsShort),c.selectMonths&&void 0==d?f.node("select",f.group({min:0,max:11,i:1,node:"option",item:function(a){return[e[a],0,"value="+a+(k.month==a?" selected":"")+(k.year==m.year&&a<m.month||k.year==n.year&&a>n.month?" disabled":"")]}}),c.klass.selectMonth+" browser-default",(a?"":"disabled")+" "+f.ariaAttr({controls:b.$node[0].id+"_table"})+' title="'+c.labelMonthSelect+'"'):"short_months"==d?null!=i?f.node("div",e[i.month]):f.node("div",e[k.month]):f.node("div",e[k.month],c.klass.month)},r=function(d){var e=k.year,g=c.selectYears===!0?5:~~(c.selectYears/2);if(g){var h=m.year,i=n.year,j=e-g,l=e+g;if(h>j&&(l+=h-j,j=h),i<l){var o=j-h,p=l-i;j-=o>p?p:o,l=i}if(c.selectYears&&void 0==d)return f.node("select",f.group({min:j,max:l,i:1,node:"option",item:function(a){return[a,0,"value="+a+(e==a?" selected":"")]}}),c.klass.selectYear+" browser-default",(a?"":"disabled")+" "+f.ariaAttr({controls:b.$node[0].id+"_table"})+' title="'+c.labelYearSelect+'"')}return"raw"==d?f.node("div",e):f.node("div",e,c.klass.year)};return createDayLabel=function(){return null!=i?f.node("div",i.date):f.node("div",h.date)},createWeekdayLabel=function(){var a;a=null!=i?i.day:h.day;var b=c.weekdaysFull[a];return b},f.node("div",f.node("div",createWeekdayLabel(),"picker__weekday-display")+f.node("div",q("short_months"),c.klass.month_display)+f.node("div",createDayLabel(),c.klass.day_display)+f.node("div",r("raw"),c.klass.year_display),c.klass.date_display)+f.node("div",f.node("div",(c.selectYears?q()+r():q()+r())+p()+p(1),c.klass.header)+f.node("table",o+f.node("tbody",f.group({min:0,max:e-1,i:1,node:"tr",item:function(a){var e=c.firstDay&&0===b.create([k.year,k.month,1]).day?-7:0;return[f.group({min:d*a-k.day+e+1,max:function(){return this.min+d-1},i:1,node:"td",item:function(a){a=b.create([k.year,k.month,a+(c.firstDay?1:0)]);var d=i&&i.pick==a.pick,e=j&&j.pick==a.pick,g=l&&b.disabled(a)||a.pick<m.pick||a.pick>n.pick,o=f.trigger(b.formats.toString,b,[c.format,a]);return[f.node("div",a.date,function(b){return b.push(k.month==a.month?c.klass.infocus:c.klass.outfocus),h.pick==a.pick&&b.push(c.klass.now),d&&b.push(c.klass.selected),e&&b.push(c.klass.highlighted),g&&b.push(c.klass.disabled),b.join(" ")}([c.klass.day]),"data-pick="+a.pick+" "+f.ariaAttr({role:"gridcell",label:o,selected:!(!d||b.$node.val()!==o)||null,activedescendant:!!e||null,disabled:!!g||null})),"",f.ariaAttr({role:"presentation"})]}})]}})),c.klass.table,'id="'+b.$node[0].id+'_table" '+f.ariaAttr({role:"grid",controls:b.$node[0].id,readonly:!0})),c.klass.calendar_container)+f.node("div",f.node("button",c.today,"btn-flat picker__today","type=button data-pick="+h.pick+(a&&!b.disabled(h)?"":" disabled")+" "+f.ariaAttr({controls:b.$node[0].id}))+f.node("button",c.clear,"btn-flat picker__clear","type=button data-clear=1"+(a?"":" disabled")+" "+f.ariaAttr({controls:b.$node[0].id}))+f.node("button",c.close,"btn-flat picker__close","type=button data-close=true "+(a?"":" disabled")+" "+f.ariaAttr({controls:b.$node[0].id})),c.klass.footer)},c.defaults=function(a){return{labelMonthNext:"Next month",labelMonthPrev:"Previous month",labelMonthSelect:"Select a month",labelYearSelect:"Select a year",monthsFull:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],weekdaysFull:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],weekdaysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],weekdaysLetter:["S","M","T","W","T","F","S"],today:"Today",clear:"Clear",close:"Close",format:"d mmmm, yyyy",klass:{table:a+"table",header:a+"header",date_display:a+"date-display",day_display:a+"day-display",month_display:a+"month-display",year_display:a+"year-display",calendar_container:a+"calendar-container",navPrev:a+"nav--prev",navNext:a+"nav--next",navDisabled:a+"nav--disabled",month:a+"month",year:a+"year",selectMonth:a+"select--month",selectYear:a+"select--year",weekdays:a+"weekday",day:a+"day",disabled:a+"day--disabled",selected:a+"day--selected",highlighted:a+"day--highlighted",now:a+"day--today",infocus:a+"day--infocus",outfocus:a+"day--outfocus",footer:a+"footer",buttonClear:a+"button--clear",buttonToday:a+"button--today",buttonClose:a+"button--close"}}}(a.klasses().picker+"__"),a.extend("pickadate",c)}),function(a){function b(){var b=+a(this).attr("data-length"),c=+a(this).val().length,d=c<=b;a(this).parent().find('span[class="character-counter"]').html(c+"/"+b),e(d,a(this))}function c(b){var c=b.parent().find('span[class="character-counter"]');c.length||(c=a("<span/>").addClass("character-counter").css("float","right").css("font-size","12px").css("height",1),b.parent().append(c))}function d(){a(this).parent().find('span[class="character-counter"]').html("")}function e(a,b){var c=b.hasClass("invalid");a&&c?b.removeClass("invalid"):a||c||(b.removeClass("valid"),b.addClass("invalid"))}a.fn.characterCounter=function(){return this.each(function(){var e=a(this),f=e.parent().find('span[class="character-counter"]');if(!f.length){var g=void 0!==e.attr("data-length");g&&(e.on("input",b),e.on("focus",b),e.on("blur",d),c(e))}})},a(document).ready(function(){a("input, textarea").characterCounter()})}(jQuery),function(a){var b={init:function(b){var c={duration:200,dist:-100,shift:0,padding:0,fullWidth:!1,indicators:!1,noWrap:!1,onCycleTo:null};return b=a.extend(c,b),this.each(function(){function c(){"undefined"!=typeof window.ontouchstart&&(J[0].addEventListener("touchstart",l),J[0].addEventListener("touchmove",m),J[0].addEventListener("touchend",n)),J[0].addEventListener("mousedown",l),J[0].addEventListener("mousemove",m),J[0].addEventListener("mouseup",n),J[0].addEventListener("mouseleave",n),J[0].addEventListener("click",j)}function d(a){return a.targetTouches&&a.targetTouches.length>=1?a.targetTouches[0].clientX:a.clientX}function e(a){return a.targetTouches&&a.targetTouches.length>=1?a.targetTouches[0].clientY:a.clientY}function f(a){return a>=v?a%v:a<0?f(v+a%v):a}function g(c){var d,e,g,h,i,j,k,l=s;if(r="number"==typeof c?c:r,s=Math.floor((r+u/2)/u),g=r-s*u,h=g<0?1:-1,i=-h*g*2/u,e=v>>1,b.fullWidth?k="translateX(0)":(k="translateX("+(J[0].clientWidth-p)/2+"px) ",k+="translateY("+(J[0].clientHeight-q)/2+"px)"),K){var m=s%v,n=I.find(".indicator-item.active");n.index()!==m&&(n.removeClass("active"),I.find(".indicator-item").eq(m).addClass("active"))}for((!b.noWrap||s>=0&&s<v)&&(j=o[f(s)],a(j).hasClass("active")||(J.find(".carousel-item").removeClass("active"),a(j).addClass("active")),j.style[C]=k+" translateX("+-g/2+"px) translateX("+h*b.shift*i*d+"px) translateZ("+b.dist*i+"px)",j.style.zIndex=0,b.fullWidth?tweenedOpacity=1:tweenedOpacity=1-.2*i,j.style.opacity=tweenedOpacity,j.style.display="block"),d=1;d<=e;++d)b.fullWidth?(zTranslation=b.dist,tweenedOpacity=d===e&&g<0?1-i:1):(zTranslation=b.dist*(2*d+i*h),tweenedOpacity=1-.2*(2*d+i*h)),(!b.noWrap||s+d<v)&&(j=o[f(s+d)],j.style[C]=k+" translateX("+(b.shift+(u*d-g)/2)+"px) translateZ("+zTranslation+"px)",j.style.zIndex=-d,j.style.opacity=tweenedOpacity,j.style.display="block"),b.fullWidth?(zTranslation=b.dist,tweenedOpacity=d===e&&g>0?1-i:1):(zTranslation=b.dist*(2*d-i*h),tweenedOpacity=1-.2*(2*d-i*h)),(!b.noWrap||s-d>=0)&&(j=o[f(s-d)],j.style[C]=k+" translateX("+(-b.shift+(-u*d-g)/2)+"px) translateZ("+zTranslation+"px)",j.style.zIndex=-d,j.style.opacity=tweenedOpacity,j.style.display="block");if((!b.noWrap||s>=0&&s<v)&&(j=o[f(s)],j.style[C]=k+" translateX("+-g/2+"px) translateX("+h*b.shift*i+"px) translateZ("+b.dist*i+"px)",j.style.zIndex=0,b.fullWidth?tweenedOpacity=1:tweenedOpacity=1-.2*i,j.style.opacity=tweenedOpacity,j.style.display="block"),l!==s&&"function"==typeof b.onCycleTo){var t=J.find(".carousel-item").eq(f(s));b.onCycleTo.call(this,t,G)}}function h(){var a,b,c,d;a=Date.now(),b=a-E,E=a,c=r-D,D=r,d=1e3*c/(1+b),B=.8*d+.2*B}function i(){var a,c;z&&(a=Date.now()-E,c=z*Math.exp(-a/b.duration),c>2||c<-2?(g(A-c),requestAnimationFrame(i)):g(A))}function j(c){if(G)return c.preventDefault(),c.stopPropagation(),!1;if(!b.fullWidth){var d=a(c.target).closest(".carousel-item").index(),e=s%v-d;0!==e&&(c.preventDefault(),c.stopPropagation()),k(d)}}function k(a){var c=s%v-a;b.noWrap||(c<0?Math.abs(c+v)<Math.abs(c)&&(c+=v):c>0&&Math.abs(c-v)<c&&(c-=v)),c<0?J.trigger("carouselNext",[Math.abs(c)]):c>0&&J.trigger("carouselPrev",[c])}function l(a){t=!0,G=!1,H=!1,w=d(a),x=e(a),B=z=0,D=r,E=Date.now(),clearInterval(F),F=setInterval(h,100)}function m(a){var b,c,f;if(t)if(b=d(a),y=e(a),c=w-b,f=Math.abs(x-y),f<30&&!H)(c>2||c<-2)&&(G=!0,w=b,g(r+c));else{if(G)return a.preventDefault(),a.stopPropagation(),!1;H=!0}if(G)return a.preventDefault(),a.stopPropagation(),!1}function n(a){if(t)return t=!1,clearInterval(F),A=r,(B>10||B<-10)&&(z=.9*B,A=r+z),A=Math.round(A/u)*u,b.noWrap&&(A>=u*(v-1)?A=u*(v-1):A<0&&(A=0)),z=A-r,E=Date.now(),requestAnimationFrame(i),G&&(a.preventDefault(),a.stopPropagation()),!1}var o,p,q,r,s,t,u,v,w,x,z,A,B,C,D,E,F,G,H,I=a('<ul class="indicators"></ul>'),J=a(this),K=J.attr("data-indicators")||b.indicators;if(J.hasClass("initialized"))return a(this).trigger("carouselNext",[1e-6]),!0;if(b.fullWidth){b.dist=0;var L=J.find(".carousel-item img").first();L.length?imageHeight=L.on("load",function(){J.css("height",a(this).height())}):(imageHeight=J.find(".carousel-item").first().height(),J.css("height",imageHeight)),K&&J.find(".carousel-fixed-item").addClass("with-indicators")}J.addClass("initialized"),t=!1,r=A=0,o=[],p=J.find(".carousel-item").first().innerWidth(),q=J.find(".carousel-item").first().innerHeight(),u=2*p+b.padding,J.find(".carousel-item").each(function(b){if(o.push(a(this)[0]),K){var c=a('<li class="indicator-item"></li>');0===b&&c.addClass("active"),c.click(function(b){b.stopPropagation();var c=a(this).index();k(c)}),I.append(c)}}),K&&J.append(I),v=o.length,C="transform",["webkit","Moz","O","ms"].every(function(a){var b=a+"Transform";return"undefined"==typeof document.body.style[b]||(C=b,!1)}),a(window).on("resize.carousel",function(){b.fullWidth?(p=J.find(".carousel-item").first().innerWidth(),q=J.find(".carousel-item").first().innerHeight(),u=2*p+b.padding,r=2*s*p,A=r):g()}),c(),g(r),a(this).on("carouselNext",function(a,b){void 0===b&&(b=1),A=u*Math.round(r/u)+u*b,r!==A&&(z=A-r,E=Date.now(),requestAnimationFrame(i))}),a(this).on("carouselPrev",function(a,b){void 0===b&&(b=1),A=u*Math.round(r/u)-u*b,r!==A&&(z=A-r,E=Date.now(),requestAnimationFrame(i))}),a(this).on("carouselSet",function(a,b){void 0===b&&(b=0),k(b)})})},next:function(b){a(this).trigger("carouselNext",[b])},prev:function(b){a(this).trigger("carouselPrev",[b])},set:function(b){a(this).trigger("carouselSet",[b])}};a.fn.carousel=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.carousel"):b.init.apply(this,arguments)}}(jQuery);
\ No newline at end of file
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/typeahead.js b/utils/test/vnfcatalogue/VNF_Catalogue/public/3rd_party/typeahead.js
deleted file mode 100644 (file)
index 11235e7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * typeahead.js 0.10.4
- * https://github.com/twitter/typeahead.js
- * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
- */
-
-!function(a){var b=function(){"use strict";return{isMsie:function(){return/(msie|trident)/i.test(navigator.userAgent)?navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2]:!1},isBlankString:function(a){return!a||/^\s*$/.test(a)},escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(a){return"string"==typeof a},isNumber:function(a){return"number"==typeof a},isArray:a.isArray,isFunction:a.isFunction,isObject:a.isPlainObject,isUndefined:function(a){return"undefined"==typeof a},toStr:function(a){return b.isUndefined(a)||null===a?"":a+""},bind:a.proxy,each:function(b,c){function d(a,b){return c(b,a)}a.each(b,d)},map:a.map,filter:a.grep,every:function(b,c){var d=!0;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?void 0:!1}),!!d):d},some:function(b,c){var d=!1;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?!1:void 0}),!!d):d},mixin:a.extend,getUniqueId:function(){var a=0;return function(){return a++}}(),templatify:function(b){function c(){return String(b)}return a.isFunction(b)?b:c},defer:function(a){setTimeout(a,0)},debounce:function(a,b,c){var d,e;return function(){var f,g,h=this,i=arguments;return f=function(){d=null,c||(e=a.apply(h,i))},g=c&&!d,clearTimeout(d),d=setTimeout(f,b),g&&(e=a.apply(h,i)),e}},throttle:function(a,b){var c,d,e,f,g,h;return g=0,h=function(){g=new Date,e=null,f=a.apply(c,d)},function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,0>=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},noop:function(){}}}(),c="0.10.4",d=function(){"use strict";function a(a){return a=b.toStr(a),a?a.split(/\s+/):[]}function c(a){return a=b.toStr(a),a?a.split(/\W+/):[]}function d(a){return function(){var c=[].slice.call(arguments,0);return function(d){var e=[];return b.each(c,function(c){e=e.concat(a(b.toStr(d[c])))}),e}}}return{nonword:c,whitespace:a,obj:{nonword:d(c),whitespace:d(a)}}}(),e=function(){"use strict";function c(c){this.maxSize=b.isNumber(c)?c:100,this.reset(),this.maxSize<=0&&(this.set=this.get=a.noop)}function d(){this.head=this.tail=null}function e(a,b){this.key=a,this.val=b,this.prev=this.next=null}return b.mixin(c.prototype,{set:function(a,b){var c,d=this.list.tail;this.size>=this.maxSize&&(this.list.remove(d),delete this.hash[d.key]),(c=this.hash[a])?(c.val=b,this.list.moveToFront(c)):(c=new e(a,b),this.list.add(c),this.hash[a]=c,this.size++)},get:function(a){var b=this.hash[a];return b?(this.list.moveToFront(b),b.val):void 0},reset:function(){this.size=0,this.hash={},this.list=new d}}),b.mixin(d.prototype,{add:function(a){this.head&&(a.next=this.head,this.head.prev=a),this.head=a,this.tail=this.tail||a},remove:function(a){a.prev?a.prev.next=a.next:this.head=a.next,a.next?a.next.prev=a.prev:this.tail=a.prev},moveToFront:function(a){this.remove(a),this.add(a)}}),c}(),f=function(){"use strict";function a(a){this.prefix=["__",a,"__"].join(""),this.ttlKey="__ttl__",this.keyMatcher=new RegExp("^"+b.escapeRegExChars(this.prefix))}function c(){return(new Date).getTime()}function d(a){return JSON.stringify(b.isUndefined(a)?null:a)}function e(a){return JSON.parse(a)}var f,g;try{f=window.localStorage,f.setItem("~~~","!"),f.removeItem("~~~")}catch(h){f=null}return g=f&&window.JSON?{_prefix:function(a){return this.prefix+a},_ttlKey:function(a){return this._prefix(a)+this.ttlKey},get:function(a){return this.isExpired(a)&&this.remove(a),e(f.getItem(this._prefix(a)))},set:function(a,e,g){return b.isNumber(g)?f.setItem(this._ttlKey(a),d(c()+g)):f.removeItem(this._ttlKey(a)),f.setItem(this._prefix(a),d(e))},remove:function(a){return f.removeItem(this._ttlKey(a)),f.removeItem(this._prefix(a)),this},clear:function(){var a,b,c=[],d=f.length;for(a=0;d>a;a++)(b=f.key(a)).match(this.keyMatcher)&&c.push(b.replace(this.keyMatcher,""));for(a=c.length;a--;)this.remove(c[a]);return this},isExpired:function(a){var d=e(f.getItem(this._ttlKey(a)));return b.isNumber(d)&&c()>d?!0:!1}}:{get:b.noop,set:b.noop,remove:b.noop,clear:b.noop,isExpired:b.noop},b.mixin(a.prototype,g),a}(),g=function(){"use strict";function c(b){b=b||{},this.cancelled=!1,this.lastUrl=null,this._send=b.transport?d(b.transport):a.ajax,this._get=b.rateLimiter?b.rateLimiter(this._get):this._get,this._cache=b.cache===!1?new e(0):i}function d(c){return function(d,e){function f(a){b.defer(function(){h.resolve(a)})}function g(a){b.defer(function(){h.reject(a)})}var h=a.Deferred();return c(d,e,f,g),h}}var f=0,g={},h=6,i=new e(10);return c.setMaxPendingRequests=function(a){h=a},c.resetCache=function(){i.reset()},b.mixin(c.prototype,{_get:function(a,b,c){function d(b){c&&c(null,b),k._cache.set(a,b)}function e(){c&&c(!0)}function i(){f--,delete g[a],k.onDeckRequestArgs&&(k._get.apply(k,k.onDeckRequestArgs),k.onDeckRequestArgs=null)}var j,k=this;this.cancelled||a!==this.lastUrl||((j=g[a])?j.done(d).fail(e):h>f?(f++,g[a]=this._send(a,b).done(d).fail(e).always(i)):this.onDeckRequestArgs=[].slice.call(arguments,0))},get:function(a,c,d){var e;return b.isFunction(c)&&(d=c,c={}),this.cancelled=!1,this.lastUrl=a,(e=this._cache.get(a))?b.defer(function(){d&&d(null,e)}):this._get(a,c,d),!!e},cancel:function(){this.cancelled=!0}}),c}(),h=function(){"use strict";function c(b){b=b||{},b.datumTokenizer&&b.queryTokenizer||a.error("datumTokenizer and queryTokenizer are both required"),this.datumTokenizer=b.datumTokenizer,this.queryTokenizer=b.queryTokenizer,this.reset()}function d(a){return a=b.filter(a,function(a){return!!a}),a=b.map(a,function(a){return a.toLowerCase()})}function e(){return{ids:[],children:{}}}function f(a){for(var b={},c=[],d=0,e=a.length;e>d;d++)b[a[d]]||(b[a[d]]=!0,c.push(a[d]));return c}function g(a,b){function c(a,b){return a-b}var d=0,e=0,f=[];a=a.sort(c),b=b.sort(c);for(var g=a.length,h=b.length;g>d&&h>e;)a[d]<b[e]?d++:a[d]>b[e]?e++:(f.push(a[d]),d++,e++);return f}return b.mixin(c.prototype,{bootstrap:function(a){this.datums=a.datums,this.trie=a.trie},add:function(a){var c=this;a=b.isArray(a)?a:[a],b.each(a,function(a){var f,g;f=c.datums.push(a)-1,g=d(c.datumTokenizer(a)),b.each(g,function(a){var b,d,g;for(b=c.trie,d=a.split("");g=d.shift();)b=b.children[g]||(b.children[g]=e()),b.ids.push(f)})})},get:function(a){var c,e,h=this;return c=d(this.queryTokenizer(a)),b.each(c,function(a){var b,c,d,f;if(e&&0===e.length)return!1;for(b=h.trie,c=a.split("");b&&(d=c.shift());)b=b.children[d];return b&&0===c.length?(f=b.ids.slice(0),void(e=e?g(e,f):f)):(e=[],!1)}),e?b.map(f(e),function(a){return h.datums[a]}):[]},reset:function(){this.datums=[],this.trie=e()},serialize:function(){return{datums:this.datums,trie:this.trie}}}),c}(),i=function(){"use strict";function d(a){return a.local||null}function e(d){var e,f;return f={url:null,thumbprint:"",ttl:864e5,filter:null,ajax:{}},(e=d.prefetch||null)&&(e=b.isString(e)?{url:e}:e,e=b.mixin(f,e),e.thumbprint=c+e.thumbprint,e.ajax.type=e.ajax.type||"GET",e.ajax.dataType=e.ajax.dataType||"json",!e.url&&a.error("prefetch requires url to be set")),e}function f(c){function d(a){return function(c){return b.debounce(c,a)}}function e(a){return function(c){return b.throttle(c,a)}}var f,g;return g={url:null,cache:!0,wildcard:"%QUERY",replace:null,rateLimitBy:"debounce",rateLimitWait:300,send:null,filter:null,ajax:{}},(f=c.remote||null)&&(f=b.isString(f)?{url:f}:f,f=b.mixin(g,f),f.rateLimiter=/^throttle$/i.test(f.rateLimitBy)?e(f.rateLimitWait):d(f.rateLimitWait),f.ajax.type=f.ajax.type||"GET",f.ajax.dataType=f.ajax.dataType||"json",delete f.rateLimitBy,delete f.rateLimitWait,!f.url&&a.error("remote requires url to be set")),f}return{local:d,prefetch:e,remote:f}}();!function(c){"use strict";function e(b){b&&(b.local||b.prefetch||b.remote)||a.error("one of local, prefetch, or remote is required"),this.limit=b.limit||5,this.sorter=j(b.sorter),this.dupDetector=b.dupDetector||k,this.local=i.local(b),this.prefetch=i.prefetch(b),this.remote=i.remote(b),this.cacheKey=this.prefetch?this.prefetch.cacheKey||this.prefetch.url:null,this.index=new h({datumTokenizer:b.datumTokenizer,queryTokenizer:b.queryTokenizer}),this.storage=this.cacheKey?new f(this.cacheKey):null}function j(a){function c(b){return b.sort(a)}function d(a){return a}return b.isFunction(a)?c:d}function k(){return!1}var l,m;return l=c.Bloodhound,m={data:"data",protocol:"protocol",thumbprint:"thumbprint"},c.Bloodhound=e,e.noConflict=function(){return c.Bloodhound=l,e},e.tokenizers=d,b.mixin(e.prototype,{_loadPrefetch:function(b){function c(a){f.clear(),f.add(b.filter?b.filter(a):a),f._saveToStorage(f.index.serialize(),b.thumbprint,b.ttl)}var d,e,f=this;return(d=this._readFromStorage(b.thumbprint))?(this.index.bootstrap(d),e=a.Deferred().resolve()):e=a.ajax(b.url,b.ajax).done(c),e},_getFromRemote:function(a,b){function c(a,c){b(a?[]:f.remote.filter?f.remote.filter(c):c)}var d,e,f=this;if(this.transport)return a=a||"",e=encodeURIComponent(a),d=this.remote.replace?this.remote.replace(this.remote.url,a):this.remote.url.replace(this.remote.wildcard,e),this.transport.get(d,this.remote.ajax,c)},_cancelLastRemoteRequest:function(){this.transport&&this.transport.cancel()},_saveToStorage:function(a,b,c){this.storage&&(this.storage.set(m.data,a,c),this.storage.set(m.protocol,location.protocol,c),this.storage.set(m.thumbprint,b,c))},_readFromStorage:function(a){var b,c={};return this.storage&&(c.data=this.storage.get(m.data),c.protocol=this.storage.get(m.protocol),c.thumbprint=this.storage.get(m.thumbprint)),b=c.thumbprint!==a||c.protocol!==location.protocol,c.data&&!b?c.data:null},_initialize:function(){function c(){e.add(b.isFunction(f)?f():f)}var d,e=this,f=this.local;return d=this.prefetch?this._loadPrefetch(this.prefetch):a.Deferred().resolve(),f&&d.done(c),this.transport=this.remote?new g(this.remote):null,this.initPromise=d.promise()},initialize:function(a){return!this.initPromise||a?this._initialize():this.initPromise},add:function(a){this.index.add(a)},get:function(a,c){function d(a){var d=f.slice(0);b.each(a,function(a){var c;return c=b.some(d,function(b){return e.dupDetector(a,b)}),!c&&d.push(a),d.length<e.limit}),c&&c(e.sorter(d))}var e=this,f=[],g=!1;f=this.index.get(a),f=this.sorter(f).slice(0,this.limit),f.length<this.limit?g=this._getFromRemote(a,d):this._cancelLastRemoteRequest(),g||(f.length>0||!this.transport)&&c&&c(f)},clear:function(){this.index.reset()},clearPrefetchCache:function(){this.storage&&this.storage.clear()},clearRemoteCache:function(){this.transport&&g.resetCache()},ttAdapter:function(){return b.bind(this.get,this)}}),e}(this);var j=function(){return{wrapper:'<span class="twitter-typeahead"></span>',dropdown:'<span class="tt-dropdown-menu"></span>',dataset:'<div class="tt-dataset-%CLASS%"></div>',suggestions:'<span class="tt-suggestions"></span>',suggestion:'<div class="tt-suggestion"></div>'}}(),k=function(){"use strict";var a={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none",opacity:"1"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},dropdown:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},suggestions:{display:"block"},suggestion:{whiteSpace:"nowrap",cursor:"pointer"},suggestionChild:{whiteSpace:"normal"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:" 0"}};return b.isMsie()&&b.mixin(a.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),b.isMsie()&&b.isMsie()<=7&&b.mixin(a.input,{marginTop:"-1px"}),a}(),l=function(){"use strict";function c(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el)}var d="typeahead:";return b.mixin(c.prototype,{trigger:function(a){var b=[].slice.call(arguments,1);this.$el.trigger(d+a,b)}}),c}(),m=function(){"use strict";function a(a,b,c,d){var e;if(!c)return this;for(b=b.split(i),c=d?h(c,d):c,this._callbacks=this._callbacks||{};e=b.shift();)this._callbacks[e]=this._callbacks[e]||{sync:[],async:[]},this._callbacks[e][a].push(c);return this}function b(b,c,d){return a.call(this,"async",b,c,d)}function c(b,c,d){return a.call(this,"sync",b,c,d)}function d(a){var b;if(!this._callbacks)return this;for(a=a.split(i);b=a.shift();)delete this._callbacks[b];return this}function e(a){var b,c,d,e,g;if(!this._callbacks)return this;for(a=a.split(i),d=[].slice.call(arguments,1);(b=a.shift())&&(c=this._callbacks[b]);)e=f(c.sync,this,[b].concat(d)),g=f(c.async,this,[b].concat(d)),e()&&j(g);return this}function f(a,b,c){function d(){for(var d,e=0,f=a.length;!d&&f>e;e+=1)d=a[e].apply(b,c)===!1;return!d}return d}function g(){var a;return a=window.setImmediate?function(a){setImmediate(function(){a()})}:function(a){setTimeout(function(){a()},0)}}function h(a,b){return a.bind?a.bind(b):function(){a.apply(b,[].slice.call(arguments,0))}}var i=/\s+/,j=g();return{onSync:c,onAsync:b,off:d,trigger:e}}(),n=function(a){"use strict";function c(a,c,d){for(var e,f=[],g=0,h=a.length;h>g;g++)f.push(b.escapeRegExChars(a[g]));return e=d?"\\b("+f.join("|")+")\\b":"("+f.join("|")+")",c?new RegExp(e):new RegExp(e,"i")}var d={node:null,pattern:null,tagName:"strong",className:null,wordsOnly:!1,caseSensitive:!1};return function(e){function f(b){var c,d,f;return(c=h.exec(b.data))&&(f=a.createElement(e.tagName),e.className&&(f.className=e.className),d=b.splitText(c.index),d.splitText(c[0].length),f.appendChild(d.cloneNode(!0)),b.parentNode.replaceChild(f,d)),!!c}function g(a,b){for(var c,d=3,e=0;e<a.childNodes.length;e++)c=a.childNodes[e],c.nodeType===d?e+=b(c)?1:0:g(c,b)}var h;e=b.mixin({},d,e),e.node&&e.pattern&&(e.pattern=b.isArray(e.pattern)?e.pattern:[e.pattern],h=c(e.pattern,e.caseSensitive,e.wordsOnly),g(e.node,f))}}(window.document),o=function(){"use strict";function c(c){var e,f,h,i,j=this;c=c||{},c.input||a.error("input is missing"),e=b.bind(this._onBlur,this),f=b.bind(this._onFocus,this),h=b.bind(this._onKeydown,this),i=b.bind(this._onInput,this),this.$hint=a(c.hint),this.$input=a(c.input).on("blur.tt",e).on("focus.tt",f).on("keydown.tt",h),0===this.$hint.length&&(this.setHint=this.getHint=this.clearHint=this.clearHintIfInvalid=b.noop),b.isMsie()?this.$input.on("keydown.tt keypress.tt cut.tt paste.tt",function(a){g[a.which||a.keyCode]||b.defer(b.bind(j._onInput,j,a))}):this.$input.on("input.tt",i),this.query=this.$input.val(),this.$overflowHelper=d(this.$input)}function d(b){return a('<pre aria-hidden="true"></pre>').css({position:"absolute",visibility:"hidden",whiteSpace:"pre",fontFamily:b.css("font-family"),fontSize:b.css("font-size"),fontStyle:b.css("font-style"),fontVariant:b.css("font-variant"),fontWeight:b.css("font-weight"),wordSpacing:b.css("word-spacing"),letterSpacing:b.css("letter-spacing"),textIndent:b.css("text-indent"),textRendering:b.css("text-rendering"),textTransform:b.css("text-transform")}).insertAfter(b)}function e(a,b){return c.normalizeQuery(a)===c.normalizeQuery(b)}function f(a){return a.altKey||a.ctrlKey||a.metaKey||a.shiftKey}var g;return g={9:"tab",27:"esc",37:"left",39:"right",13:"enter",38:"up",40:"down"},c.normalizeQuery=function(a){return(a||"").replace(/^\s*/g,"").replace(/\s{2,}/g," ")},b.mixin(c.prototype,m,{_onBlur:function(){this.resetInputValue(),this.trigger("blurred")},_onFocus:function(){this.trigger("focused")},_onKeydown:function(a){var b=g[a.which||a.keyCode];this._managePreventDefault(b,a),b&&this._shouldTrigger(b,a)&&this.trigger(b+"Keyed",a)},_onInput:function(){this._checkInputValue()},_managePreventDefault:function(a,b){var c,d,e;switch(a){case"tab":d=this.getHint(),e=this.getInputValue(),c=d&&d!==e&&!f(b);break;case"up":case"down":c=!f(b);break;default:c=!1}c&&b.preventDefault()},_shouldTrigger:function(a,b){var c;switch(a){case"tab":c=!f(b);break;default:c=!0}return c},_checkInputValue:function(){var a,b,c;a=this.getInputValue(),b=e(a,this.query),c=b?this.query.length!==a.length:!1,this.query=a,b?c&&this.trigger("whitespaceChanged",this.query):this.trigger("queryChanged",this.query)},focus:function(){this.$input.focus()},blur:function(){this.$input.blur()},getQuery:function(){return this.query},setQuery:function(a){this.query=a},getInputValue:function(){return this.$input.val()},setInputValue:function(a,b){this.$input.val(a),b?this.clearHint():this._checkInputValue()},resetInputValue:function(){this.setInputValue(this.query,!0)},getHint:function(){return this.$hint.val()},setHint:function(a){this.$hint.val(a)},clearHint:function(){this.setHint("")},clearHintIfInvalid:function(){var a,b,c,d;a=this.getInputValue(),b=this.getHint(),c=a!==b&&0===b.indexOf(a),d=""!==a&&c&&!this.hasOverflow(),!d&&this.clearHint()},getLanguageDirection:function(){return(this.$input.css("direction")||"ltr").toLowerCase()},hasOverflow:function(){var a=this.$input.width()-2;return this.$overflowHelper.text(this.getInputValue()),this.$overflowHelper.width()>=a},isCursorAtEnd:function(){var a,c,d;return a=this.$input.val().length,c=this.$input[0].selectionStart,b.isNumber(c)?c===a:document.selection?(d=document.selection.createRange(),d.moveStart("character",-a),a===d.text.length):!0},destroy:function(){this.$hint.off(".tt"),this.$input.off(".tt"),this.$hint=this.$input=this.$overflowHelper=null}}),c}(),p=function(){"use strict";function c(c){c=c||{},c.templates=c.templates||{},c.source||a.error("missing source"),c.name&&!f(c.name)&&a.error("invalid dataset name: "+c.name),this.query=null,this.highlight=!!c.highlight,this.name=c.name||b.getUniqueId(),this.source=c.source,this.displayFn=d(c.display||c.displayKey),this.templates=e(c.templates,this.displayFn),this.$el=a(j.dataset.replace("%CLASS%",this.name))}function d(a){function c(b){return b[a]}return a=a||"value",b.isFunction(a)?a:c}function e(a,c){function d(a){return"<p>"+c(a)+"</p>"}return{empty:a.empty&&b.templatify(a.empty),header:a.header&&b.templatify(a.header),footer:a.footer&&b.templatify(a.footer),suggestion:a.suggestion||d}}function f(a){return/^[_a-zA-Z0-9-]+$/.test(a)}var g="ttDataset",h="ttValue",i="ttDatum";return c.extractDatasetName=function(b){return a(b).data(g)},c.extractValue=function(b){return a(b).data(h)},c.extractDatum=function(b){return a(b).data(i)},b.mixin(c.prototype,m,{_render:function(c,d){function e(){return p.templates.empty({query:c,isEmpty:!0})}function f(){function e(b){var c;return c=a(j.suggestion).append(p.templates.suggestion(b)).data(g,p.name).data(h,p.displayFn(b)).data(i,b),c.children().each(function(){a(this).css(k.suggestionChild)}),c}var f,l;return f=a(j.suggestions).css(k.suggestions),l=b.map(d,e),f.append.apply(f,l),p.highlight&&n({className:"tt-highlight",node:f[0],pattern:c}),f}function l(){return p.templates.header({query:c,isEmpty:!o})}function m(){return p.templates.footer({query:c,isEmpty:!o})}if(this.$el){var o,p=this;this.$el.empty(),o=d&&d.length,!o&&this.templates.empty?this.$el.html(e()).prepend(p.templates.header?l():null).append(p.templates.footer?m():null):o&&this.$el.html(f()).prepend(p.templates.header?l():null).append(p.templates.footer?m():null),this.trigger("rendered")}},getRoot:function(){return this.$el},update:function(a){function b(b){c.canceled||a!==c.query||c._render(a,b)}var c=this;this.query=a,this.canceled=!1,this.source(a,b)},cancel:function(){this.canceled=!0},clear:function(){this.cancel(),this.$el.empty(),this.trigger("rendered")},isEmpty:function(){return this.$el.is(":empty")},destroy:function(){this.$el=null}}),c}(),q=function(){"use strict";function c(c){var e,f,g,h=this;c=c||{},c.menu||a.error("menu is required"),this.isOpen=!1,this.isEmpty=!0,this.datasets=b.map(c.datasets,d),e=b.bind(this._onSuggestionClick,this),f=b.bind(this._onSuggestionMouseEnter,this),g=b.bind(this._onSuggestionMouseLeave,this),this.$menu=a(c.menu).on("click.tt",".tt-suggestion",e).on("mouseenter.tt",".tt-suggestion",f).on("mouseleave.tt",".tt-suggestion",g),b.each(this.datasets,function(a){h.$menu.append(a.getRoot()),a.onSync("rendered",h._onRendered,h)})}function d(a){return new p(a)}return b.mixin(c.prototype,m,{_onSuggestionClick:function(b){this.trigger("suggestionClicked",a(b.currentTarget))},_onSuggestionMouseEnter:function(b){this._removeCursor(),this._setCursor(a(b.currentTarget),!0)},_onSuggestionMouseLeave:function(){this._removeCursor()},_onRendered:function(){function a(a){return a.isEmpty()}this.isEmpty=b.every(this.datasets,a),this.isEmpty?this._hide():this.isOpen&&this._show(),this.trigger("datasetRendered")},_hide:function(){this.$menu.hide()},_show:function(){this.$menu.css("display","block")},_getSuggestions:function(){return this.$menu.find(".tt-suggestion")},_getCursor:function(){return this.$menu.find(".tt-cursor").first()},_setCursor:function(a,b){a.first().addClass("tt-cursor"),!b&&this.trigger("cursorMoved")},_removeCursor:function(){this._getCursor().removeClass("tt-cursor")},_moveCursor:function(a){var b,c,d,e;if(this.isOpen){if(c=this._getCursor(),b=this._getSuggestions(),this._removeCursor(),d=b.index(c)+a,d=(d+1)%(b.length+1)-1,-1===d)return void this.trigger("cursorRemoved");-1>d&&(d=b.length-1),this._setCursor(e=b.eq(d)),this._ensureVisible(e)}},_ensureVisible:function(a){var b,c,d,e;b=a.position().top,c=b+a.outerHeight(!0),d=this.$menu.scrollTop(),e=this.$menu.height()+parseInt(this.$menu.css("paddingTop"),10)+parseInt(this.$menu.css("paddingBottom"),10),0>b?this.$menu.scrollTop(d+b):c>e&&this.$menu.scrollTop(d+(c-e))},close:function(){this.isOpen&&(this.isOpen=!1,this._removeCursor(),this._hide(),this.trigger("closed"))},open:function(){this.isOpen||(this.isOpen=!0,!this.isEmpty&&this._show(),this.trigger("opened"))},setLanguageDirection:function(a){this.$menu.css("ltr"===a?k.ltr:k.rtl)},moveCursorUp:function(){this._moveCursor(-1)},moveCursorDown:function(){this._moveCursor(1)},getDatumForSuggestion:function(a){var b=null;return a.length&&(b={raw:p.extractDatum(a),value:p.extractValue(a),datasetName:p.extractDatasetName(a)}),b},getDatumForCursor:function(){return this.getDatumForSuggestion(this._getCursor().first())},getDatumForTopSuggestion:function(){return this.getDatumForSuggestion(this._getSuggestions().first())},update:function(a){function c(b){b.update(a)}b.each(this.datasets,c)},empty:function(){function a(a){a.clear()}b.each(this.datasets,a),this.isEmpty=!0},isVisible:function(){return this.isOpen&&!this.isEmpty},destroy:function(){function a(a){a.destroy()}this.$menu.off(".tt"),this.$menu=null,b.each(this.datasets,a)}}),c}(),r=function(){"use strict";function c(c){var e,f,g;c=c||{},c.input||a.error("missing input"),this.isActivated=!1,this.autoselect=!!c.autoselect,this.minLength=b.isNumber(c.minLength)?c.minLength:1,this.$node=d(c.input,c.withHint),e=this.$node.find(".tt-dropdown-menu"),f=this.$node.find(".tt-input"),g=this.$node.find(".tt-hint"),f.on("blur.tt",function(a){var c,d,g;c=document.activeElement,d=e.is(c),g=e.has(c).length>0,b.isMsie()&&(d||g)&&(a.preventDefault(),a.stopImmediatePropagation(),b.defer(function(){f.focus()}))}),e.on("mousedown.tt",function(a){a.preventDefault()}),this.eventBus=c.eventBus||new l({el:f}),this.dropdown=new q({menu:e,datasets:c.datasets}).onSync("suggestionClicked",this._onSuggestionClicked,this).onSync("cursorMoved",this._onCursorMoved,this).onSync("cursorRemoved",this._onCursorRemoved,this).onSync("opened",this._onOpened,this).onSync("closed",this._onClosed,this).onAsync("datasetRendered",this._onDatasetRendered,this),this.input=new o({input:f,hint:g}).onSync("focused",this._onFocused,this).onSync("blurred",this._onBlurred,this).onSync("enterKeyed",this._onEnterKeyed,this).onSync("tabKeyed",this._onTabKeyed,this).onSync("escKeyed",this._onEscKeyed,this).onSync("upKeyed",this._onUpKeyed,this).onSync("downKeyed",this._onDownKeyed,this).onSync("leftKeyed",this._onLeftKeyed,this).onSync("rightKeyed",this._onRightKeyed,this).onSync("queryChanged",this._onQueryChanged,this).onSync("whitespaceChanged",this._onWhitespaceChanged,this),this._setLanguageDirection()}function d(b,c){var d,f,h,i;d=a(b),f=a(j.wrapper).css(k.wrapper),h=a(j.dropdown).css(k.dropdown),i=d.clone().css(k.hint).css(e(d)),i.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder required").prop("readonly",!0).attr({autocomplete:"off",spellcheck:"false",tabindex:-1}),d.data(g,{dir:d.attr("dir"),autocomplete:d.attr("autocomplete"),spellcheck:d.attr("spellcheck"),style:d.attr("style")}),d.addClass("tt-input").attr({autocomplete:"off",spellcheck:!1}).css(c?k.input:k.inputWithNoHint);try{!d.attr("dir")&&d.attr("dir","auto")}catch(l){}return d.wrap(f).parent().prepend(c?i:null).append(h)}function e(a){return{backgroundAttachment:a.css("background-attachment"),backgroundClip:a.css("background-clip"),backgroundColor:a.css("background-color"),backgroundImage:a.css("background-image"),backgroundOrigin:a.css("background-origin"),backgroundPosition:a.css("background-position"),backgroundRepeat:a.css("background-repeat"),backgroundSize:a.css("background-size")}}function f(a){var c=a.find(".tt-input");b.each(c.data(g),function(a,d){b.isUndefined(a)?c.removeAttr(d):c.attr(d,a)}),c.detach().removeData(g).removeClass("tt-input").insertAfter(a),a.remove()}var g="ttAttrs";return b.mixin(c.prototype,{_onSuggestionClicked:function(a,b){var c;(c=this.dropdown.getDatumForSuggestion(b))&&this._select(c)},_onCursorMoved:function(){var a=this.dropdown.getDatumForCursor();this.input.setInputValue(a.value,!0),this.eventBus.trigger("cursorchanged",a.raw,a.datasetName)},_onCursorRemoved:function(){this.input.resetInputValue(),this._updateHint()},_onDatasetRendered:function(){this._updateHint()},_onOpened:function(){this._updateHint(),this.eventBus.trigger("opened")},_onClosed:function(){this.input.clearHint(),this.eventBus.trigger("closed")},_onFocused:function(){this.isActivated=!0,this.dropdown.open()},_onBlurred:function(){this.isActivated=!1,this.dropdown.empty(),this.dropdown.close()},_onEnterKeyed:function(a,b){var c,d;c=this.dropdown.getDatumForCursor(),d=this.dropdown.getDatumForTopSuggestion(),c?(this._select(c),b.preventDefault()):this.autoselect&&d&&(this._select(d),b.preventDefault())},_onTabKeyed:function(a,b){var c;(c=this.dropdown.getDatumForCursor())?(this._select(c),b.preventDefault()):this._autocomplete(!0)},_onEscKeyed:function(){this.dropdown.close(),this.input.resetInputValue()},_onUpKeyed:function(){var a=this.input.getQuery();this.dropdown.isEmpty&&a.length>=this.minLength?this.dropdown.update(a):this.dropdown.moveCursorUp(),this.dropdown.open()},_onDownKeyed:function(){var a=this.input.getQuery();this.dropdown.isEmpty&&a.length>=this.minLength?this.dropdown.update(a):this.dropdown.moveCursorDown(),this.dropdown.open()},_onLeftKeyed:function(){"rtl"===this.dir&&this._autocomplete()},_onRightKeyed:function(){"ltr"===this.dir&&this._autocomplete()},_onQueryChanged:function(a,b){this.input.clearHintIfInvalid(),b.length>=this.minLength?this.dropdown.update(b):this.dropdown.empty(),this.dropdown.open(),this._setLanguageDirection()},_onWhitespaceChanged:function(){this._updateHint(),this.dropdown.open()},_setLanguageDirection:function(){var a;this.dir!==(a=this.input.getLanguageDirection())&&(this.dir=a,this.$node.css("direction",a),this.dropdown.setLanguageDirection(a))},_updateHint:function(){var a,c,d,e,f,g;a=this.dropdown.getDatumForTopSuggestion(),a&&this.dropdown.isVisible()&&!this.input.hasOverflow()?(c=this.input.getInputValue(),d=o.normalizeQuery(c),e=b.escapeRegExChars(d),f=new RegExp("^(?:"+e+")(.+$)","i"),g=f.exec(a.value),g?this.input.setHint(c+g[1]):this.input.clearHint()):this.input.clearHint()},_autocomplete:function(a){var b,c,d,e;b=this.input.getHint(),c=this.input.getQuery(),d=a||this.input.isCursorAtEnd(),b&&c!==b&&d&&(e=this.dropdown.getDatumForTopSuggestion(),e&&this.input.setInputValue(e.value),this.eventBus.trigger("autocompleted",e.raw,e.datasetName))},_select:function(a){this.input.setQuery(a.value),this.input.setInputValue(a.value,!0),this._setLanguageDirection(),this.eventBus.trigger("selected",a.raw,a.datasetName),this.dropdown.close(),b.defer(b.bind(this.dropdown.empty,this.dropdown))},open:function(){this.dropdown.open()},close:function(){this.dropdown.close()},setVal:function(a){a=b.toStr(a),this.isActivated?this.input.setInputValue(a):(this.input.setQuery(a),this.input.setInputValue(a,!0)),this._setLanguageDirection()},getVal:function(){return this.input.getQuery()},destroy:function(){this.input.destroy(),this.dropdown.destroy(),f(this.$node),this.$node=null}}),c}();!function(){"use strict";var c,d,e;c=a.fn.typeahead,d="ttTypeahead",e={initialize:function(c,e){function f(){var f,g,h=a(this);b.each(e,function(a){a.highlight=!!c.highlight}),g=new r({input:h,eventBus:f=new l({el:h}),withHint:b.isUndefined(c.hint)?!0:!!c.hint,minLength:c.minLength,autoselect:c.autoselect,datasets:e}),h.data(d,g)}return e=b.isArray(e)?e:[].slice.call(arguments,1),c=c||{},this.each(f)},open:function(){function b(){var b,c=a(this);(b=c.data(d))&&b.open()}return this.each(b)},close:function(){function b(){var b,c=a(this);(b=c.data(d))&&b.close()}return this.each(b)},val:function(b){function c(){var c,e=a(this);(c=e.data(d))&&c.setVal(b)}function e(a){var b,c;return(b=a.data(d))&&(c=b.getVal()),c}return arguments.length?this.each(c):e(this.first())},destroy:function(){function b(){var b,c=a(this);(b=c.data(d))&&(b.destroy(),c.removeData(d))}return this.each(b)}},a.fn.typeahead=function(b){var c;return e[b]&&"initialize"!==b?(c=this.filter(function(){return!!a(this).data(d)}),e[b].apply(c,[].slice.call(arguments,1))):e.initialize.apply(this,arguments)},a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this}}()}(window.jQuery);
\ No newline at end of file
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/images/3rd_party/commits.png b/utils/test/vnfcatalogue/VNF_Catalogue/public/images/3rd_party/commits.png
deleted file mode 100644 (file)
index 1247621..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/images/3rd_party/commits.png and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/images/logo.png b/utils/test/vnfcatalogue/VNF_Catalogue/public/images/logo.png
deleted file mode 100644 (file)
index fe18194..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/images/logo.png and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/javascripts/global.js b/utils/test/vnfcatalogue/VNF_Catalogue/public/javascripts/global.js
deleted file mode 100644 (file)
index f610456..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*******************************************************************************\r
- * Copyright (c) 2017 Kumar Rishabh and others.\r
- *\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Apache License, Version 2.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *******************************************************************************/\r
-\r
-$(document).ready( function() {\r
-    $('select').material_select();\r
-    $('.modal').modal();\r
-    $(".button-collapse").sideNav();\r
-    $('.carousel').carousel();\r
-\r
-    $('#Search').click(function() {\r
-        var tags = $('#Tags').val().toLowerCase().split(/[ ,]+/);\r
-        window.location.href = '/search_projects?tags=' + tags;\r
-        return false;\r
-    });\r
-\r
-    $('#SearchSpan').click(function(){\r
-        var tags = $('#Tags').val().toLowerCase().split(/[ ,]+/);\r
-        window.location.href = '/search_projects?tags=' + tags;\r
-        return false;\r
-    });\r
-\r
-    $('div.form-group-custom i.material-icons').click(function(e){\r
-        var tags = $('#Tags').val().toLowerCase().split(/[ ,]+/);\r
-        window.location.href = '/search_projects?tags=' + tags;\r
-        return false;\r
-    });\r
-\r
-    $("#add_project_button").on('click',function(){\r
-        event.preventDefault();\r
-        var vnf_name = $("#vnf_name").val() ;\r
-\r
-        var formData = new FormData($('form#add_project_form')[0]);\r
-        var license = $('#license option:selected').val();\r
-        formData.append('license', license);\r
-        var opnfv_indicator = $('#opnfv_indicator option:selected').val();\r
-        formData.append('opnfv_indicator', opnfv_indicator);\r
-\r
-        $.ajax({\r
-            url: '/add_project',\r
-            type: 'post',\r
-            //dataType: 'json',\r
-            processData: false,  // tell jQuery not to process the data\r
-            contentType: false,  // tell jQuery not to set contentType\r
-            data: formData,\r
-            success: function(data) {\r
-                    $('#modal1').modal('close');\r
-                    $('form#add_project_form').trigger('reset');\r
-                    Materialize.toast('Successfully submitted the VNF!', 3000, 'rounded');\r
-            },\r
-            error: function (error) {\r
-                if(error['responseJSON']) {\r
-                    Materialize.toast(error['responseJSON']['error'], 3000, 'rounded');\r
-                } else if(error['responseText']) {\r
-                    var response_message = JSON.parse(error['responseText']);\r
-                    Materialize.toast(response_message['error'], 3000, 'rounded');\r
-                }\r
-                //$('#modal1').modal('open');\r
-            }\r
-        });\r
-    });\r
-    $("#add_tag_button").on('click',function(){\r
-        event.preventDefault();\r
-        var tag_name = $("#tag_name").val() ;\r
-\r
-        $.ajax({\r
-            url: '/add_tag',\r
-            type: 'post',\r
-            dataType: 'json',\r
-            data: $('form#add_tag_form').serialize(),\r
-            success: function(data) {\r
-                    $('#modal2').modal('close');\r
-                    $('form#add_tag_form').trigger('reset');\r
-                    Materialize.toast('Successfully submitted the TAG!', 3000, 'rounded');\r
-            },\r
-            error: function (error) {\r
-                Materialize.toast(error['responseJSON']['error'], 3000, 'rounded');\r
-            }\r
-        });\r
-    });\r
-\r
-});\r
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/javascripts/mode_edit.js b/utils/test/vnfcatalogue/VNF_Catalogue/public/javascripts/mode_edit.js
deleted file mode 100644 (file)
index 2047a92..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*******************************************************************************\r
- * Copyright (c) 2017 Kumar Rishabh and others.\r
- *\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Apache License, Version 2.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *******************************************************************************/\r
-\r
-$(document).ready( function() {\r
-\r
-    //getVnfs : get 5 main VNFs using typeahead\r
-    var getVnfs = new Bloodhound({\r
-        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('vnf_name'),\r
-        queryTokenizer: Bloodhound.tokenizers.obj.whitespace('vnf_name'),\r
-        remote: {\r
-            url: '/search_vnf?key=%QUERY',\r
-            wildcard: '%QUERY'\r
-        },\r
-        limit: 5\r
-    });\r
-\r
-    getVnfs.initialize();\r
-    $('#scrollable-dropdown-menu #vnf_name.typeahead').typeahead(\r
-    {\r
-        hint: true,\r
-        highlight: true,\r
-        minLength: 1\r
-    },\r
-    {\r
-        name: 'vnf_name',\r
-        display: 'vnf_name',\r
-        limit: 5,\r
-        source: getVnfs.ttAdapter()\r
-    });\r
-\r
-    //getTags : get 5 main tags using typeahead\r
-    var getTags = new Bloodhound({\r
-        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('tag_name'),\r
-        queryTokenizer: Bloodhound.tokenizers.obj.whitespace('tag_name'),\r
-        remote: {\r
-            url: '/search_tag?key=%QUERY',\r
-            wildcard: '%QUERY'\r
-        },\r
-        limit: 5\r
-    });\r
-\r
-    getTags.initialize();\r
-    $('#scrollable-dropdown-menu #tag_name.typeahead').typeahead(\r
-    {\r
-        hint: true,\r
-        highlight: true,\r
-        minLength: 1\r
-    },\r
-    {\r
-        name: 'tag_name',\r
-        display: 'tag_name',\r
-        limit: 5,\r
-        source: getTags.ttAdapter()\r
-    });\r
-\r
-    $("#add_vnf_tag_association_button").on('click',function(){\r
-        event.preventDefault();\r
-        var vnf_name = $("#vnf_name").val() ;\r
-\r
-        $.ajax({\r
-            url: '/vnf_tag_association',\r
-            type: 'post',\r
-            dataType: 'json',\r
-            data: $('form#add_vnf_tag_association_form').serialize(),\r
-            success: function(data) {\r
-                    $('#modal3').modal('close');\r
-                    $('form#add_vnf_tag_association_form').trigger('reset');\r
-                    Materialize.toast('Successfully added the TAG to the VNF!', 3000, 'rounded');\r
-            },\r
-            error: function (error) {\r
-                Materialize.toast(error['responseJSON']['error'], 3000, 'rounded');\r
-            }\r
-        });\r
-    });\r
-\r
-});\r
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/javascripts/search_results.js b/utils/test/vnfcatalogue/VNF_Catalogue/public/javascripts/search_results.js
deleted file mode 100644 (file)
index 26c28c9..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*******************************************************************************\r
- * Copyright (c) 2017 Kumar Rishabh and others.\r
- *\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Apache License, Version 2.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *******************************************************************************/\r
-\r
-$(document).ready( function() {\r
-    var ob = JSON.parse(json);\r
-});\r
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/3rd_party/bootstrap.css b/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/3rd_party/bootstrap.css
deleted file mode 100755 (executable)
index 6167622..0000000
+++ /dev/null
@@ -1,6757 +0,0 @@
-/*!
- * 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;
-  -webkit-text-size-adjust: 100%;
-      -ms-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 {
-  margin: .67em 0;
-  font-size: 2em;
-}
-mark {
-  color: #000;
-  background: #ff0;
-}
-small {
-  font-size: 80%;
-}
-sub,
-sup {
-  position: relative;
-  font-size: 75%;
-  line-height: 0;
-  vertical-align: baseline;
-}
-sup {
-  top: -.5em;
-}
-sub {
-  bottom: -.25em;
-}
-img {
-  border: 0;
-}
-svg:not(:root) {
-  overflow: hidden;
-}
-figure {
-  margin: 1em 40px;
-}
-hr {
-  height: 0;
-  -webkit-box-sizing: content-box;
-     -moz-box-sizing: content-box;
-          box-sizing: content-box;
-}
-pre {
-  overflow: auto;
-}
-code,
-kbd,
-pre,
-samp {
-  font-family: monospace, monospace;
-  font-size: 1em;
-}
-button,
-input,
-optgroup,
-select,
-textarea {
-  margin: 0;
-  font: inherit;
-  color: inherit;
-}
-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 {
-  padding: 0;
-  border: 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-box-sizing: content-box;
-     -moz-box-sizing: content-box;
-          box-sizing: content-box;
-  -webkit-appearance: textfield;
-}
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
-  -webkit-appearance: none;
-}
-fieldset {
-  padding: .35em .625em .75em;
-  margin: 0 2px;
-  border: 1px solid #c0c0c0;
-}
-legend {
-  padding: 0;
-  border: 0;
-}
-textarea {
-  overflow: auto;
-}
-optgroup {
-  font-weight: bold;
-}
-table {
-  border-spacing: 0;
-  border-collapse: collapse;
-}
-td,
-th {
-  padding: 0;
-}
-/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
-@media print {
-  *,
-  *:before,
-  *:after {
-    color: #000 !important;
-    text-shadow: none !important;
-    background: transparent !important;
-    -webkit-box-shadow: none !important;
-            box-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: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 14px;
-  line-height: 1.42857143;
-  color: #333;
-  background-color: #fff;
-}
-input,
-button,
-select,
-textarea {
-  font-family: inherit;
-  font-size: inherit;
-  line-height: inherit;
-}
-a {
-  color: #337ab7;
-  text-decoration: none;
-}
-a:hover,
-a:focus {
-  color: #23527c;
-  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 {
-  display: inline-block;
-  max-width: 100%;
-  height: auto;
-  padding: 4px;
-  line-height: 1.42857143;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-radius: 4px;
-  -webkit-transition: all .2s ease-in-out;
-       -o-transition: all .2s ease-in-out;
-          transition: all .2s ease-in-out;
-}
-.img-circle {
-  border-radius: 50%;
-}
-hr {
-  margin-top: 20px;
-  margin-bottom: 20px;
-  border: 0;
-  border-top: 1px solid #eee;
-}
-.sr-only {
-  position: absolute;
-  width: 1px;
-  height: 1px;
-  padding: 0;
-  margin: -1px;
-  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: inherit;
-  font-weight: 500;
-  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: #777;
-}
-h1,
-.h1,
-h2,
-.h2,
-h3,
-.h3 {
-  margin-top: 20px;
-  margin-bottom: 10px;
-}
-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: 10px;
-  margin-bottom: 10px;
-}
-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: 36px;
-}
-h2,
-.h2 {
-  font-size: 30px;
-}
-h3,
-.h3 {
-  font-size: 24px;
-}
-h4,
-.h4 {
-  font-size: 18px;
-}
-h5,
-.h5 {
-  font-size: 14px;
-}
-h6,
-.h6 {
-  font-size: 12px;
-}
-p {
-  margin: 0 0 10px;
-}
-.lead {
-  margin-bottom: 20px;
-  font-size: 16px;
-  font-weight: 300;
-  line-height: 1.4;
-}
-@media (min-width: 768px) {
-  .lead {
-    font-size: 21px;
-  }
-}
-small,
-.small {
-  font-size: 85%;
-}
-mark,
-.mark {
-  padding: .2em;
-  background-color: #fcf8e3;
-}
-.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: #777;
-}
-.text-primary {
-  color: #337ab7;
-}
-a.text-primary:hover,
-a.text-primary:focus {
-  color: #286090;
-}
-.text-success {
-  color: #3c763d;
-}
-a.text-success:hover,
-a.text-success:focus {
-  color: #2b542c;
-}
-.text-info {
-  color: #31708f;
-}
-a.text-info:hover,
-a.text-info:focus {
-  color: #245269;
-}
-.text-warning {
-  color: #8a6d3b;
-}
-a.text-warning:hover,
-a.text-warning:focus {
-  color: #66512c;
-}
-.text-danger {
-  color: #a94442;
-}
-a.text-danger:hover,
-a.text-danger:focus {
-  color: #843534;
-}
-.bg-primary {
-  color: #fff;
-  background-color: #337ab7;
-}
-a.bg-primary:hover,
-a.bg-primary:focus {
-  background-color: #286090;
-}
-.bg-success {
-  background-color: #dff0d8;
-}
-a.bg-success:hover,
-a.bg-success:focus {
-  background-color: #c1e2b3;
-}
-.bg-info {
-  background-color: #d9edf7;
-}
-a.bg-info:hover,
-a.bg-info:focus {
-  background-color: #afd9ee;
-}
-.bg-warning {
-  background-color: #fcf8e3;
-}
-a.bg-warning:hover,
-a.bg-warning:focus {
-  background-color: #f7ecb5;
-}
-.bg-danger {
-  background-color: #f2dede;
-}
-a.bg-danger:hover,
-a.bg-danger:focus {
-  background-color: #e4b9b9;
-}
-.page-header {
-  padding-bottom: 9px;
-  margin: 40px 0 20px;
-  border-bottom: 1px solid #eee;
-}
-ul,
-ol {
-  margin-top: 0;
-  margin-bottom: 10px;
-}
-ul ul,
-ol ul,
-ul ol,
-ol ol {
-  margin-bottom: 0;
-}
-.list-unstyled {
-  padding-left: 0;
-  list-style: none;
-}
-.list-inline {
-  padding-left: 0;
-  margin-left: -5px;
-  list-style: none;
-}
-.list-inline > li {
-  display: inline-block;
-  padding-right: 5px;
-  padding-left: 5px;
-}
-dl {
-  margin-top: 0;
-  margin-bottom: 20px;
-}
-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;
-    overflow: hidden;
-    clear: left;
-    text-align: right;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-  }
-  .dl-horizontal dd {
-    margin-left: 180px;
-  }
-}
-abbr[title],
-abbr[data-original-title] {
-  cursor: help;
-  border-bottom: 1px dotted #777;
-}
-.initialism {
-  font-size: 90%;
-  text-transform: uppercase;
-}
-blockquote {
-  padding: 10px 20px;
-  margin: 0 0 20px;
-  font-size: 17.5px;
-  border-left: 5px solid #eee;
-}
-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: #777;
-}
-blockquote footer:before,
-blockquote small:before,
-blockquote .small:before {
-  content: '\2014 \00A0';
-}
-.blockquote-reverse,
-blockquote.pull-right {
-  padding-right: 15px;
-  padding-left: 0;
-  text-align: right;
-  border-right: 5px solid #eee;
-  border-left: 0;
-}
-.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: 20px;
-  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: #fff;
-  background-color: #333;
-  border-radius: 3px;
-  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
-          box-shadow: inset 0 -1px 0 rgba(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: 9.5px;
-  margin: 0 0 10px;
-  font-size: 13px;
-  line-height: 1.42857143;
-  color: #333;
-  word-break: break-all;
-  word-wrap: break-word;
-  background-color: #f5f5f5;
-  border: 1px solid #ccc;
-  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 {
-  padding-right: 15px;
-  padding-left: 15px;
-  margin-right: auto;
-  margin-left: auto;
-}
-@media (min-width: 768px) {
-  .container {
-    width: 750px;
-  }
-}
-@media (min-width: 992px) {
-  .container {
-    width: 970px;
-  }
-}
-@media (min-width: 1200px) {
-  .container {
-    width: 1170px;
-  }
-}
-.container-fluid {
-  padding-right: 15px;
-  padding-left: 15px;
-  margin-right: auto;
-  margin-left: auto;
-}
-.row {
-  margin-right: -15px;
-  margin-left: -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-right: 15px;
-  padding-left: 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: #777;
-  text-align: left;
-}
-th {
-  text-align: left;
-}
-.table {
-  width: 100%;
-  max-width: 100%;
-  margin-bottom: 20px;
-}
-.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 #ddd;
-}
-.table > thead > tr > th {
-  vertical-align: bottom;
-  border-bottom: 2px solid #ddd;
-}
-.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 #ddd;
-}
-.table .table {
-  background-color: #fff;
-}
-.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 #ddd;
-}
-.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 #ddd;
-}
-.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: #f5f5f5;
-}
-table col[class*="col-"] {
-  position: static;
-  display: table-column;
-  float: none;
-}
-table td[class*="col-"],
-table th[class*="col-"] {
-  position: static;
-  display: table-cell;
-  float: none;
-}
-.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: #f5f5f5;
-}
-.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: #e8e8e8;
-}
-.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: #dff0d8;
-}
-.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: #d0e9c6;
-}
-.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: #d9edf7;
-}
-.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: #c4e3f3;
-}
-.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: #fcf8e3;
-}
-.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: #faf2cc;
-}
-.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: #f2dede;
-}
-.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: #ebcccc;
-}
-.table-responsive {
-  min-height: .01%;
-  overflow-x: auto;
-}
-@media screen and (max-width: 767px) {
-  .table-responsive {
-    width: 100%;
-    margin-bottom: 15px;
-    overflow-y: hidden;
-    -ms-overflow-style: -ms-autohiding-scrollbar;
-    border: 1px solid #ddd;
-  }
-  .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 {
-  min-width: 0;
-  padding: 0;
-  margin: 0;
-  border: 0;
-}
-legend {
-  display: block;
-  width: 100%;
-  padding: 0;
-  margin-bottom: 20px;
-  font-size: 21px;
-  line-height: inherit;
-  color: #333;
-  border: 0;
-  border-bottom: 1px solid #e5e5e5;
-}
-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: 7px;
-  font-size: 14px;
-  line-height: 1.42857143;
-  color: #555;
-}
-.form-control {
-  display: block;
-  width: 100%;
-  height: 34px;
-  padding: 6px 12px;
-  font-size: 14px;
-  line-height: 1.42857143;
-  color: #555;
-  background-color: #fff;
-  background-image: none;
-  border: 1px solid #ccc;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(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: #66afe9;
-  outline: 0;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
-          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
-}
-.form-control::-moz-placeholder {
-  color: #999;
-  opacity: 1;
-}
-.form-control:-ms-input-placeholder {
-  color: #999;
-}
-.form-control::-webkit-input-placeholder {
-  color: #999;
-}
-.form-control::-ms-expand {
-  background-color: transparent;
-  border: 0;
-}
-.form-control[disabled],
-.form-control[readonly],
-fieldset[disabled] .form-control {
-  background-color: #eee;
-  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: 34px;
-  }
-  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: 30px;
-  }
-  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: 46px;
-  }
-}
-.form-group {
-  margin-bottom: 15px;
-}
-.radio,
-.checkbox {
-  position: relative;
-  display: block;
-  margin-top: 10px;
-  margin-bottom: 10px;
-}
-.radio label,
-.checkbox label {
-  min-height: 20px;
-  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-top: 4px \9;
-  margin-left: -20px;
-}
-.radio + .radio,
-.checkbox + .checkbox {
-  margin-top: -5px;
-}
-.radio-inline,
-.checkbox-inline {
-  position: relative;
-  display: inline-block;
-  padding-left: 20px;
-  margin-bottom: 0;
-  font-weight: normal;
-  vertical-align: middle;
-  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 {
-  min-height: 34px;
-  padding-top: 7px;
-  padding-bottom: 7px;
-  margin-bottom: 0;
-}
-.form-control-static.input-lg,
-.form-control-static.input-sm {
-  padding-right: 0;
-  padding-left: 0;
-}
-.input-sm {
-  height: 30px;
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-select.input-sm {
-  height: 30px;
-  line-height: 30px;
-}
-textarea.input-sm,
-select[multiple].input-sm {
-  height: auto;
-}
-.form-group-sm .form-control {
-  height: 30px;
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-.form-group-sm select.form-control {
-  height: 30px;
-  line-height: 30px;
-}
-.form-group-sm textarea.form-control,
-.form-group-sm select[multiple].form-control {
-  height: auto;
-}
-.form-group-sm .form-control-static {
-  height: 30px;
-  min-height: 32px;
-  padding: 6px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-}
-.input-lg {
-  height: 46px;
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-  border-radius: 6px;
-}
-select.input-lg {
-  height: 46px;
-  line-height: 46px;
-}
-textarea.input-lg,
-select[multiple].input-lg {
-  height: auto;
-}
-.form-group-lg .form-control {
-  height: 46px;
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-  border-radius: 6px;
-}
-.form-group-lg select.form-control {
-  height: 46px;
-  line-height: 46px;
-}
-.form-group-lg textarea.form-control,
-.form-group-lg select[multiple].form-control {
-  height: auto;
-}
-.form-group-lg .form-control-static {
-  height: 46px;
-  min-height: 38px;
-  padding: 11px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-}
-.has-feedback {
-  position: relative;
-}
-.has-feedback .form-control {
-  padding-right: 42.5px;
-}
-.form-control-feedback {
-  position: absolute;
-  top: 0;
-  right: 0;
-  z-index: 2;
-  display: block;
-  width: 34px;
-  height: 34px;
-  line-height: 34px;
-  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: 46px;
-  height: 46px;
-  line-height: 46px;
-}
-.input-sm + .form-control-feedback,
-.input-group-sm + .form-control-feedback,
-.form-group-sm .form-control + .form-control-feedback {
-  width: 30px;
-  height: 30px;
-  line-height: 30px;
-}
-.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: #3c763d;
-}
-.has-success .form-control {
-  border-color: #3c763d;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-}
-.has-success .form-control:focus {
-  border-color: #2b542c;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
-}
-.has-success .input-group-addon {
-  color: #3c763d;
-  background-color: #dff0d8;
-  border-color: #3c763d;
-}
-.has-success .form-control-feedback {
-  color: #3c763d;
-}
-.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: #8a6d3b;
-}
-.has-warning .form-control {
-  border-color: #8a6d3b;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-}
-.has-warning .form-control:focus {
-  border-color: #66512c;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
-}
-.has-warning .input-group-addon {
-  color: #8a6d3b;
-  background-color: #fcf8e3;
-  border-color: #8a6d3b;
-}
-.has-warning .form-control-feedback {
-  color: #8a6d3b;
-}
-.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: #a94442;
-}
-.has-error .form-control {
-  border-color: #a94442;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-}
-.has-error .form-control:focus {
-  border-color: #843534;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
-}
-.has-error .input-group-addon {
-  color: #a94442;
-  background-color: #f2dede;
-  border-color: #a94442;
-}
-.has-error .form-control-feedback {
-  color: #a94442;
-}
-.has-feedback label ~ .form-control-feedback {
-  top: 25px;
-}
-.has-feedback label.sr-only ~ .form-control-feedback {
-  top: 0;
-}
-.help-block {
-  display: block;
-  margin-top: 5px;
-  margin-bottom: 10px;
-  color: #737373;
-}
-@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 {
-  padding-top: 7px;
-  margin-top: 0;
-  margin-bottom: 0;
-}
-.form-horizontal .radio,
-.form-horizontal .checkbox {
-  min-height: 27px;
-}
-.form-horizontal .form-group {
-  margin-right: -15px;
-  margin-left: -15px;
-}
-@media (min-width: 768px) {
-  .form-horizontal .control-label {
-    padding-top: 7px;
-    margin-bottom: 0;
-    text-align: right;
-  }
-}
-.form-horizontal .has-feedback .form-control-feedback {
-  right: 15px;
-}
-@media (min-width: 768px) {
-  .form-horizontal .form-group-lg .control-label {
-    padding-top: 11px;
-    font-size: 18px;
-  }
-}
-@media (min-width: 768px) {
-  .form-horizontal .form-group-sm .control-label {
-    padding-top: 6px;
-    font-size: 12px;
-  }
-}
-.btn {
-  display: inline-block;
-  padding: 6px 12px;
-  margin-bottom: 0;
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 1.42857143;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: middle;
-  -ms-touch-action: manipulation;
-      touch-action: manipulation;
-  cursor: pointer;
-  -webkit-user-select: none;
-     -moz-user-select: none;
-      -ms-user-select: none;
-          user-select: none;
-  background-image: none;
-  border: 1px solid transparent;
-  border-radius: 4px;
-}
-.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: #333;
-  text-decoration: none;
-}
-.btn:active,
-.btn.active {
-  background-image: none;
-  outline: 0;
-  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-}
-.btn.disabled,
-.btn[disabled],
-fieldset[disabled] .btn {
-  cursor: not-allowed;
-  filter: alpha(opacity=65);
-  -webkit-box-shadow: none;
-          box-shadow: none;
-  opacity: .65;
-}
-a.btn.disabled,
-fieldset[disabled] a.btn {
-  pointer-events: none;
-}
-.btn-default {
-  color: #333;
-  background-color: #fff;
-  border-color: #ccc;
-}
-.btn-default:focus,
-.btn-default.focus {
-  color: #333;
-  background-color: #e6e6e6;
-  border-color: #8c8c8c;
-}
-.btn-default:hover {
-  color: #333;
-  background-color: #e6e6e6;
-  border-color: #adadad;
-}
-.btn-default:active,
-.btn-default.active,
-.open > .dropdown-toggle.btn-default {
-  color: #333;
-  background-color: #e6e6e6;
-  border-color: #adadad;
-}
-.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: #333;
-  background-color: #d4d4d4;
-  border-color: #8c8c8c;
-}
-.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: #fff;
-  border-color: #ccc;
-}
-.btn-default .badge {
-  color: #fff;
-  background-color: #333;
-}
-.btn-primary {
-  color: #fff;
-  background-color: #337ab7;
-  border-color: #2e6da4;
-}
-.btn-primary:focus,
-.btn-primary.focus {
-  color: #fff;
-  background-color: #286090;
-  border-color: #122b40;
-}
-.btn-primary:hover {
-  color: #fff;
-  background-color: #286090;
-  border-color: #204d74;
-}
-.btn-primary:active,
-.btn-primary.active,
-.open > .dropdown-toggle.btn-primary {
-  color: #fff;
-  background-color: #286090;
-  border-color: #204d74;
-}
-.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: #fff;
-  background-color: #204d74;
-  border-color: #122b40;
-}
-.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: #337ab7;
-  border-color: #2e6da4;
-}
-.btn-primary .badge {
-  color: #337ab7;
-  background-color: #fff;
-}
-.btn-success {
-  color: #fff;
-  background-color: #5cb85c;
-  border-color: #4cae4c;
-}
-.btn-success:focus,
-.btn-success.focus {
-  color: #fff;
-  background-color: #449d44;
-  border-color: #255625;
-}
-.btn-success:hover {
-  color: #fff;
-  background-color: #449d44;
-  border-color: #398439;
-}
-.btn-success:active,
-.btn-success.active,
-.open > .dropdown-toggle.btn-success {
-  color: #fff;
-  background-color: #449d44;
-  border-color: #398439;
-}
-.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: #fff;
-  background-color: #398439;
-  border-color: #255625;
-}
-.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: #5cb85c;
-  border-color: #4cae4c;
-}
-.btn-success .badge {
-  color: #5cb85c;
-  background-color: #fff;
-}
-.btn-info {
-  color: #fff;
-  background-color: #5bc0de;
-  border-color: #46b8da;
-}
-.btn-info:focus,
-.btn-info.focus {
-  color: #fff;
-  background-color: #31b0d5;
-  border-color: #1b6d85;
-}
-.btn-info:hover {
-  color: #fff;
-  background-color: #31b0d5;
-  border-color: #269abc;
-}
-.btn-info:active,
-.btn-info.active,
-.open > .dropdown-toggle.btn-info {
-  color: #fff;
-  background-color: #31b0d5;
-  border-color: #269abc;
-}
-.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: #fff;
-  background-color: #269abc;
-  border-color: #1b6d85;
-}
-.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: #5bc0de;
-  border-color: #46b8da;
-}
-.btn-info .badge {
-  color: #5bc0de;
-  background-color: #fff;
-}
-.btn-warning {
-  color: #fff;
-  background-color: #f0ad4e;
-  border-color: #eea236;
-}
-.btn-warning:focus,
-.btn-warning.focus {
-  color: #fff;
-  background-color: #ec971f;
-  border-color: #985f0d;
-}
-.btn-warning:hover {
-  color: #fff;
-  background-color: #ec971f;
-  border-color: #d58512;
-}
-.btn-warning:active,
-.btn-warning.active,
-.open > .dropdown-toggle.btn-warning {
-  color: #fff;
-  background-color: #ec971f;
-  border-color: #d58512;
-}
-.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: #fff;
-  background-color: #d58512;
-  border-color: #985f0d;
-}
-.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: #f0ad4e;
-  border-color: #eea236;
-}
-.btn-warning .badge {
-  color: #f0ad4e;
-  background-color: #fff;
-}
-.btn-danger {
-  color: #fff;
-  background-color: #d9534f;
-  border-color: #d43f3a;
-}
-.btn-danger:focus,
-.btn-danger.focus {
-  color: #fff;
-  background-color: #c9302c;
-  border-color: #761c19;
-}
-.btn-danger:hover {
-  color: #fff;
-  background-color: #c9302c;
-  border-color: #ac2925;
-}
-.btn-danger:active,
-.btn-danger.active,
-.open > .dropdown-toggle.btn-danger {
-  color: #fff;
-  background-color: #c9302c;
-  border-color: #ac2925;
-}
-.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: #fff;
-  background-color: #ac2925;
-  border-color: #761c19;
-}
-.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: #d9534f;
-  border-color: #d43f3a;
-}
-.btn-danger .badge {
-  color: #d9534f;
-  background-color: #fff;
-}
-.btn-link {
-  font-weight: normal;
-  color: #337ab7;
-  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: #23527c;
-  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: #777;
-  text-decoration: none;
-}
-.btn-lg,
-.btn-group-lg > .btn {
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-  border-radius: 6px;
-}
-.btn-sm,
-.btn-group-sm > .btn {
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-  border-radius: 3px;
-}
-.btn-xs,
-.btn-group-xs > .btn {
-  padding: 1px 5px;
-  font-size: 12px;
-  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 .15s linear;
-       -o-transition: opacity .15s linear;
-          transition: opacity .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-timing-function: ease;
-       -o-transition-timing-function: ease;
-          transition-timing-function: ease;
-  -webkit-transition-duration: .35s;
-       -o-transition-duration: .35s;
-          transition-duration: .35s;
-  -webkit-transition-property: height, visibility;
-       -o-transition-property: height, visibility;
-          transition-property: height, visibility;
-}
-.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;
-  font-size: 14px;
-  text-align: left;
-  list-style: none;
-  background-color: #fff;
-  -webkit-background-clip: padding-box;
-          background-clip: padding-box;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, .15);
-  border-radius: 4px;
-  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
-          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
-}
-.dropdown-menu.pull-right {
-  right: 0;
-  left: auto;
-}
-.dropdown-menu .divider {
-  height: 1px;
-  margin: 9px 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: #333;
-  white-space: nowrap;
-}
-.dropdown-menu > li > a:hover,
-.dropdown-menu > li > a:focus {
-  color: #262626;
-  text-decoration: none;
-  background-color: #f5f5f5;
-}
-.dropdown-menu > .active > a,
-.dropdown-menu > .active > a:hover,
-.dropdown-menu > .active > a:focus {
-  color: #fff;
-  text-decoration: none;
-  background-color: #337ab7;
-  outline: 0;
-}
-.dropdown-menu > .disabled > a,
-.dropdown-menu > .disabled > a:hover,
-.dropdown-menu > .disabled > a:focus {
-  color: #777;
-}
-.dropdown-menu > .disabled > a:hover,
-.dropdown-menu > .disabled > a:focus {
-  text-decoration: none;
-  cursor: not-allowed;
-  background-color: transparent;
-  background-image: none;
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
-}
-.open > .dropdown-menu {
-  display: block;
-}
-.open > a {
-  outline: 0;
-}
-.dropdown-menu-right {
-  right: 0;
-  left: auto;
-}
-.dropdown-menu-left {
-  right: auto;
-  left: 0;
-}
-.dropdown-header {
-  display: block;
-  padding: 3px 20px;
-  font-size: 12px;
-  line-height: 1.42857143;
-  color: #777;
-  white-space: nowrap;
-}
-.dropdown-backdrop {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 990;
-}
-.pull-right > .dropdown-menu {
-  right: 0;
-  left: auto;
-}
-.dropup .caret,
-.navbar-fixed-bottom .dropdown .caret {
-  content: "";
-  border-top: 0;
-  border-bottom: 4px dashed;
-  border-bottom: 4px solid \9;
-}
-.dropup .dropdown-menu,
-.navbar-fixed-bottom .dropdown .dropdown-menu {
-  top: auto;
-  bottom: 100%;
-  margin-bottom: 2px;
-}
-@media (min-width: 768px) {
-  .navbar-right .dropdown-menu {
-    right: 0;
-    left: auto;
-  }
-  .navbar-right .dropdown-menu-left {
-    right: auto;
-    left: 0;
-  }
-}
-.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-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-.btn-group > .btn:last-child:not(:first-child),
-.btn-group > .dropdown-toggle:not(:first-child) {
-  border-top-left-radius: 0;
-  border-bottom-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-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group .dropdown-toggle:active,
-.btn-group.open .dropdown-toggle {
-  outline: 0;
-}
-.btn-group > .btn + .dropdown-toggle {
-  padding-right: 8px;
-  padding-left: 8px;
-}
-.btn-group > .btn-lg + .dropdown-toggle {
-  padding-right: 12px;
-  padding-left: 12px;
-}
-.btn-group.open .dropdown-toggle {
-  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
-          box-shadow: inset 0 3px 5px rgba(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-left-radius: 4px;
-  border-top-right-radius: 4px;
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.btn-group-vertical > .btn:last-child:not(:first-child) {
-  border-top-left-radius: 0;
-  border-top-right-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-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.btn-group-justified {
-  display: table;
-  width: 100%;
-  table-layout: fixed;
-  border-collapse: separate;
-}
-.btn-group-justified > .btn,
-.btn-group-justified > .btn-group {
-  display: table-cell;
-  float: none;
-  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-right: 0;
-  padding-left: 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: 46px;
-  padding: 10px 16px;
-  font-size: 18px;
-  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: 46px;
-  line-height: 46px;
-}
-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: 30px;
-  padding: 5px 10px;
-  font-size: 12px;
-  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: 30px;
-  line-height: 30px;
-}
-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: 6px 12px;
-  font-size: 14px;
-  font-weight: normal;
-  line-height: 1;
-  color: #555;
-  text-align: center;
-  background-color: #eee;
-  border: 1px solid #ccc;
-  border-radius: 4px;
-}
-.input-group-addon.input-sm {
-  padding: 5px 10px;
-  font-size: 12px;
-  border-radius: 3px;
-}
-.input-group-addon.input-lg {
-  padding: 10px 16px;
-  font-size: 18px;
-  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-top-right-radius: 0;
-  border-bottom-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-top-left-radius: 0;
-  border-bottom-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 {
-  padding-left: 0;
-  margin-bottom: 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: #eee;
-}
-.nav > li.disabled > a {
-  color: #777;
-}
-.nav > li.disabled > a:hover,
-.nav > li.disabled > a:focus {
-  color: #777;
-  text-decoration: none;
-  cursor: not-allowed;
-  background-color: transparent;
-}
-.nav .open > a,
-.nav .open > a:hover,
-.nav .open > a:focus {
-  background-color: #eee;
-  border-color: #337ab7;
-}
-.nav .nav-divider {
-  height: 1px;
-  margin: 9px 0;
-  overflow: hidden;
-  background-color: #e5e5e5;
-}
-.nav > li > a > img {
-  max-width: none;
-}
-.nav-tabs {
-  border-bottom: 1px solid #ddd;
-}
-.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: #eee #eee #ddd;
-}
-.nav-tabs > li.active > a,
-.nav-tabs > li.active > a:hover,
-.nav-tabs > li.active > a:focus {
-  color: #555;
-  cursor: default;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-bottom-color: transparent;
-}
-.nav-tabs.nav-justified {
-  width: 100%;
-  border-bottom: 0;
-}
-.nav-tabs.nav-justified > li {
-  float: none;
-}
-.nav-tabs.nav-justified > li > a {
-  margin-bottom: 5px;
-  text-align: center;
-}
-.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 #ddd;
-}
-@media (min-width: 768px) {
-  .nav-tabs.nav-justified > li > a {
-    border-bottom: 1px solid #ddd;
-    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: #fff;
-  }
-}
-.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: #fff;
-  background-color: #337ab7;
-}
-.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 {
-  margin-bottom: 5px;
-  text-align: center;
-}
-.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 #ddd;
-}
-@media (min-width: 768px) {
-  .nav-tabs-justified > li > a {
-    border-bottom: 1px solid #ddd;
-    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: #fff;
-  }
-}
-.tab-content > .tab-pane {
-  display: none;
-}
-.tab-content > .active {
-  display: block;
-}
-.nav-tabs .dropdown-menu {
-  margin-top: -1px;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.navbar {
-  position: relative;
-  min-height: 50px;
-  margin-bottom: 20px;
-  border: 1px solid transparent;
-}
-@media (min-width: 768px) {
-  .navbar {
-    border-radius: 4px;
-  }
-}
-@media (min-width: 768px) {
-  .navbar-header {
-    float: left;
-  }
-}
-.navbar-collapse {
-  padding-right: 15px;
-  padding-left: 15px;
-  overflow-x: visible;
-  -webkit-overflow-scrolling: touch;
-  border-top: 1px solid transparent;
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
-}
-.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-right: 0;
-    padding-left: 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;
-  height: 50px;
-  padding: 15px 15px;
-  font-size: 18px;
-  line-height: 20px;
-}
-.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;
-  padding: 9px 10px;
-  margin-top: 8px;
-  margin-right: 15px;
-  margin-bottom: 8px;
-  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: 7.5px -15px;
-}
-.navbar-nav > li > a {
-  padding-top: 10px;
-  padding-bottom: 10px;
-  line-height: 20px;
-}
-@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: 20px;
-  }
-  .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: 15px;
-    padding-bottom: 15px;
-  }
-}
-.navbar-form {
-  padding: 10px 15px;
-  margin-top: 8px;
-  margin-right: -15px;
-  margin-bottom: 8px;
-  margin-left: -15px;
-  border-top: 1px solid transparent;
-  border-bottom: 1px solid transparent;
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
-}
-@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;
-    padding-top: 0;
-    padding-bottom: 0;
-    margin-right: 0;
-    margin-left: 0;
-    border: 0;
-    -webkit-box-shadow: none;
-            box-shadow: none;
-  }
-}
-.navbar-nav > li > .dropdown-menu {
-  margin-top: 0;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
-  margin-bottom: 0;
-  border-top-left-radius: 4px;
-  border-top-right-radius: 4px;
-  border-bottom-right-radius: 0;
-  border-bottom-left-radius: 0;
-}
-.navbar-btn {
-  margin-top: 8px;
-  margin-bottom: 8px;
-}
-.navbar-btn.btn-sm {
-  margin-top: 10px;
-  margin-bottom: 10px;
-}
-.navbar-btn.btn-xs {
-  margin-top: 14px;
-  margin-bottom: 14px;
-}
-.navbar-text {
-  margin-top: 15px;
-  margin-bottom: 15px;
-}
-@media (min-width: 768px) {
-  .navbar-text {
-    float: left;
-    margin-right: 15px;
-    margin-left: 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: #f8f8f8;
-  border-color: #e7e7e7;
-}
-.navbar-default .navbar-brand {
-  color: #777;
-}
-.navbar-default .navbar-brand:hover,
-.navbar-default .navbar-brand:focus {
-  color: #5e5e5e;
-  background-color: transparent;
-}
-.navbar-default .navbar-text {
-  color: #777;
-}
-.navbar-default .navbar-nav > li > a {
-  color: #777;
-}
-.navbar-default .navbar-nav > li > a:hover,
-.navbar-default .navbar-nav > li > a:focus {
-  color: #333;
-  background-color: transparent;
-}
-.navbar-default .navbar-nav > .active > a,
-.navbar-default .navbar-nav > .active > a:hover,
-.navbar-default .navbar-nav > .active > a:focus {
-  color: #555;
-  background-color: #e7e7e7;
-}
-.navbar-default .navbar-nav > .disabled > a,
-.navbar-default .navbar-nav > .disabled > a:hover,
-.navbar-default .navbar-nav > .disabled > a:focus {
-  color: #ccc;
-  background-color: transparent;
-}
-.navbar-default .navbar-toggle {
-  border-color: #ddd;
-}
-.navbar-default .navbar-toggle:hover,
-.navbar-default .navbar-toggle:focus {
-  background-color: #ddd;
-}
-.navbar-default .navbar-toggle .icon-bar {
-  background-color: #888;
-}
-.navbar-default .navbar-collapse,
-.navbar-default .navbar-form {
-  border-color: #e7e7e7;
-}
-.navbar-default .navbar-nav > .open > a,
-.navbar-default .navbar-nav > .open > a:hover,
-.navbar-default .navbar-nav > .open > a:focus {
-  color: #555;
-  background-color: #e7e7e7;
-}
-@media (max-width: 767px) {
-  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
-    color: #777;
-  }
-  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
-  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
-    color: #333;
-    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: #555;
-    background-color: #e7e7e7;
-  }
-  .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: #ccc;
-    background-color: transparent;
-  }
-}
-.navbar-default .navbar-link {
-  color: #777;
-}
-.navbar-default .navbar-link:hover {
-  color: #333;
-}
-.navbar-default .btn-link {
-  color: #777;
-}
-.navbar-default .btn-link:hover,
-.navbar-default .btn-link:focus {
-  color: #333;
-}
-.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: #ccc;
-}
-.navbar-inverse {
-  background-color: #222;
-  border-color: #080808;
-}
-.navbar-inverse .navbar-brand {
-  color: #9d9d9d;
-}
-.navbar-inverse .navbar-brand:hover,
-.navbar-inverse .navbar-brand:focus {
-  color: #fff;
-  background-color: transparent;
-}
-.navbar-inverse .navbar-text {
-  color: #9d9d9d;
-}
-.navbar-inverse .navbar-nav > li > a {
-  color: #9d9d9d;
-}
-.navbar-inverse .navbar-nav > li > a:hover,
-.navbar-inverse .navbar-nav > li > a:focus {
-  color: #fff;
-  background-color: transparent;
-}
-.navbar-inverse .navbar-nav > .active > a,
-.navbar-inverse .navbar-nav > .active > a:hover,
-.navbar-inverse .navbar-nav > .active > a:focus {
-  color: #fff;
-  background-color: #080808;
-}
-.navbar-inverse .navbar-nav > .disabled > a,
-.navbar-inverse .navbar-nav > .disabled > a:hover,
-.navbar-inverse .navbar-nav > .disabled > a:focus {
-  color: #444;
-  background-color: transparent;
-}
-.navbar-inverse .navbar-toggle {
-  border-color: #333;
-}
-.navbar-inverse .navbar-toggle:hover,
-.navbar-inverse .navbar-toggle:focus {
-  background-color: #333;
-}
-.navbar-inverse .navbar-toggle .icon-bar {
-  background-color: #fff;
-}
-.navbar-inverse .navbar-collapse,
-.navbar-inverse .navbar-form {
-  border-color: #101010;
-}
-.navbar-inverse .navbar-nav > .open > a,
-.navbar-inverse .navbar-nav > .open > a:hover,
-.navbar-inverse .navbar-nav > .open > a:focus {
-  color: #fff;
-  background-color: #080808;
-}
-@media (max-width: 767px) {
-  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
-    border-color: #080808;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
-    background-color: #080808;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
-    color: #9d9d9d;
-  }
-  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
-  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
-    color: #fff;
-    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: #fff;
-    background-color: #080808;
-  }
-  .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: #444;
-    background-color: transparent;
-  }
-}
-.navbar-inverse .navbar-link {
-  color: #9d9d9d;
-}
-.navbar-inverse .navbar-link:hover {
-  color: #fff;
-}
-.navbar-inverse .btn-link {
-  color: #9d9d9d;
-}
-.navbar-inverse .btn-link:hover,
-.navbar-inverse .btn-link:focus {
-  color: #fff;
-}
-.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: #444;
-}
-.breadcrumb {
-  padding: 8px 15px;
-  margin-bottom: 20px;
-  list-style: none;
-  background-color: #f5f5f5;
-  border-radius: 4px;
-}
-.breadcrumb > li {
-  display: inline-block;
-}
-.breadcrumb > li + li:before {
-  padding: 0 5px;
-  color: #ccc;
-  content: "/\00a0";
-}
-.breadcrumb > .active {
-  color: #777;
-}
-.pagination {
-  display: inline-block;
-  padding-left: 0;
-  margin: 20px 0;
-  border-radius: 4px;
-}
-.pagination > li {
-  display: inline;
-}
-.pagination > li > a,
-.pagination > li > span {
-  position: relative;
-  float: left;
-  padding: 6px 12px;
-  margin-left: -1px;
-  line-height: 1.42857143;
-  color: #337ab7;
-  text-decoration: none;
-  background-color: #fff;
-  border: 1px solid #ddd;
-}
-.pagination > li:first-child > a,
-.pagination > li:first-child > span {
-  margin-left: 0;
-  border-top-left-radius: 4px;
-  border-bottom-left-radius: 4px;
-}
-.pagination > li:last-child > a,
-.pagination > li:last-child > span {
-  border-top-right-radius: 4px;
-  border-bottom-right-radius: 4px;
-}
-.pagination > li > a:hover,
-.pagination > li > span:hover,
-.pagination > li > a:focus,
-.pagination > li > span:focus {
-  z-index: 2;
-  color: #23527c;
-  background-color: #eee;
-  border-color: #ddd;
-}
-.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: #fff;
-  cursor: default;
-  background-color: #337ab7;
-  border-color: #337ab7;
-}
-.pagination > .disabled > span,
-.pagination > .disabled > span:hover,
-.pagination > .disabled > span:focus,
-.pagination > .disabled > a,
-.pagination > .disabled > a:hover,
-.pagination > .disabled > a:focus {
-  color: #777;
-  cursor: not-allowed;
-  background-color: #fff;
-  border-color: #ddd;
-}
-.pagination-lg > li > a,
-.pagination-lg > li > span {
-  padding: 10px 16px;
-  font-size: 18px;
-  line-height: 1.3333333;
-}
-.pagination-lg > li:first-child > a,
-.pagination-lg > li:first-child > span {
-  border-top-left-radius: 6px;
-  border-bottom-left-radius: 6px;
-}
-.pagination-lg > li:last-child > a,
-.pagination-lg > li:last-child > span {
-  border-top-right-radius: 6px;
-  border-bottom-right-radius: 6px;
-}
-.pagination-sm > li > a,
-.pagination-sm > li > span {
-  padding: 5px 10px;
-  font-size: 12px;
-  line-height: 1.5;
-}
-.pagination-sm > li:first-child > a,
-.pagination-sm > li:first-child > span {
-  border-top-left-radius: 3px;
-  border-bottom-left-radius: 3px;
-}
-.pagination-sm > li:last-child > a,
-.pagination-sm > li:last-child > span {
-  border-top-right-radius: 3px;
-  border-bottom-right-radius: 3px;
-}
-.pager {
-  padding-left: 0;
-  margin: 20px 0;
-  text-align: center;
-  list-style: none;
-}
-.pager li {
-  display: inline;
-}
-.pager li > a,
-.pager li > span {
-  display: inline-block;
-  padding: 5px 14px;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  border-radius: 15px;
-}
-.pager li > a:hover,
-.pager li > a:focus {
-  text-decoration: none;
-  background-color: #eee;
-}
-.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: #777;
-  cursor: not-allowed;
-  background-color: #fff;
-}
-.label {
-  display: inline;
-  padding: .2em .6em .3em;
-  font-size: 75%;
-  font-weight: bold;
-  line-height: 1;
-  color: #fff;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: baseline;
-  border-radius: .25em;
-}
-a.label:hover,
-a.label:focus {
-  color: #fff;
-  text-decoration: none;
-  cursor: pointer;
-}
-.label:empty {
-  display: none;
-}
-.btn .label {
-  position: relative;
-  top: -1px;
-}
-.label-default {
-  background-color: #777;
-}
-.label-default[href]:hover,
-.label-default[href]:focus {
-  background-color: #5e5e5e;
-}
-.label-primary {
-  background-color: #337ab7;
-}
-.label-primary[href]:hover,
-.label-primary[href]:focus {
-  background-color: #286090;
-}
-.label-success {
-  background-color: #5cb85c;
-}
-.label-success[href]:hover,
-.label-success[href]:focus {
-  background-color: #449d44;
-}
-.label-info {
-  background-color: #5bc0de;
-}
-.label-info[href]:hover,
-.label-info[href]:focus {
-  background-color: #31b0d5;
-}
-.label-warning {
-  background-color: #f0ad4e;
-}
-.label-warning[href]:hover,
-.label-warning[href]:focus {
-  background-color: #ec971f;
-}
-.label-danger {
-  background-color: #d9534f;
-}
-.label-danger[href]:hover,
-.label-danger[href]:focus {
-  background-color: #c9302c;
-}
-.badge {
-  display: inline-block;
-  min-width: 10px;
-  padding: 3px 7px;
-  font-size: 12px;
-  font-weight: bold;
-  line-height: 1;
-  color: #fff;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: middle;
-  background-color: #777;
-  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: #fff;
-  text-decoration: none;
-  cursor: pointer;
-}
-.list-group-item.active > .badge,
-.nav-pills > .active > a > .badge {
-  color: #337ab7;
-  background-color: #fff;
-}
-.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: #eee;
-}
-.jumbotron h1,
-.jumbotron .h1 {
-  color: inherit;
-}
-.jumbotron p {
-  margin-bottom: 15px;
-  font-size: 21px;
-  font-weight: 200;
-}
-.jumbotron > hr {
-  border-top-color: #d5d5d5;
-}
-.container .jumbotron,
-.container-fluid .jumbotron {
-  padding-right: 15px;
-  padding-left: 15px;
-  border-radius: 6px;
-}
-.jumbotron .container {
-  max-width: 100%;
-}
-@media screen and (min-width: 768px) {
-  .jumbotron {
-    padding-top: 48px;
-    padding-bottom: 48px;
-  }
-  .container .jumbotron,
-  .container-fluid .jumbotron {
-    padding-right: 60px;
-    padding-left: 60px;
-  }
-  .jumbotron h1,
-  .jumbotron .h1 {
-    font-size: 63px;
-  }
-}
-.thumbnail {
-  display: block;
-  padding: 4px;
-  margin-bottom: 20px;
-  line-height: 1.42857143;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  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-right: auto;
-  margin-left: auto;
-}
-a.thumbnail:hover,
-a.thumbnail:focus,
-a.thumbnail.active {
-  border-color: #337ab7;
-}
-.thumbnail .caption {
-  padding: 9px;
-  color: #333;
-}
-.alert {
-  padding: 15px;
-  margin-bottom: 20px;
-  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 {
-  color: #3c763d;
-  background-color: #dff0d8;
-  border-color: #d6e9c6;
-}
-.alert-success hr {
-  border-top-color: #c9e2b3;
-}
-.alert-success .alert-link {
-  color: #2b542c;
-}
-.alert-info {
-  color: #31708f;
-  background-color: #d9edf7;
-  border-color: #bce8f1;
-}
-.alert-info hr {
-  border-top-color: #a6e1ec;
-}
-.alert-info .alert-link {
-  color: #245269;
-}
-.alert-warning {
-  color: #8a6d3b;
-  background-color: #fcf8e3;
-  border-color: #faebcc;
-}
-.alert-warning hr {
-  border-top-color: #f7e1b5;
-}
-.alert-warning .alert-link {
-  color: #66512c;
-}
-.alert-danger {
-  color: #a94442;
-  background-color: #f2dede;
-  border-color: #ebccd1;
-}
-.alert-danger hr {
-  border-top-color: #e4b9c0;
-}
-.alert-danger .alert-link {
-  color: #843534;
-}
-@-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 {
-  height: 20px;
-  margin-bottom: 20px;
-  overflow: hidden;
-  background-color: #f5f5f5;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
-          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
-}
-.progress-bar {
-  float: left;
-  width: 0;
-  height: 100%;
-  font-size: 12px;
-  line-height: 20px;
-  color: #fff;
-  text-align: center;
-  background-color: #337ab7;
-  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
-          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
-  -webkit-transition: width .6s ease;
-       -o-transition: width .6s ease;
-          transition: width .6s ease;
-}
-.progress-striped .progress-bar,
-.progress-bar-striped {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .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: #5cb85c;
-}
-.progress-striped .progress-bar-success {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.progress-bar-info {
-  background-color: #5bc0de;
-}
-.progress-striped .progress-bar-info {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.progress-bar-warning {
-  background-color: #f0ad4e;
-}
-.progress-striped .progress-bar-warning {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.progress-bar-danger {
-  background-color: #d9534f;
-}
-.progress-striped .progress-bar-danger {
-  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
-}
-.media {
-  margin-top: 15px;
-}
-.media:first-child {
-  margin-top: 0;
-}
-.media,
-.media-body {
-  overflow: hidden;
-  zoom: 1;
-}
-.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 {
-  padding-left: 0;
-  margin-bottom: 20px;
-}
-.list-group-item {
-  position: relative;
-  display: block;
-  padding: 10px 15px;
-  margin-bottom: -1px;
-  background-color: #fff;
-  border: 1px solid #ddd;
-}
-.list-group-item:first-child {
-  border-top-left-radius: 4px;
-  border-top-right-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: #555;
-}
-a.list-group-item .list-group-item-heading,
-button.list-group-item .list-group-item-heading {
-  color: #333;
-}
-a.list-group-item:hover,
-button.list-group-item:hover,
-a.list-group-item:focus,
-button.list-group-item:focus {
-  color: #555;
-  text-decoration: none;
-  background-color: #f5f5f5;
-}
-button.list-group-item {
-  width: 100%;
-  text-align: left;
-}
-.list-group-item.disabled,
-.list-group-item.disabled:hover,
-.list-group-item.disabled:focus {
-  color: #777;
-  cursor: not-allowed;
-  background-color: #eee;
-}
-.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: #777;
-}
-.list-group-item.active,
-.list-group-item.active:hover,
-.list-group-item.active:focus {
-  z-index: 2;
-  color: #fff;
-  background-color: #337ab7;
-  border-color: #337ab7;
-}
-.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: #c7ddef;
-}
-.list-group-item-success {
-  color: #3c763d;
-  background-color: #dff0d8;
-}
-a.list-group-item-success,
-button.list-group-item-success {
-  color: #3c763d;
-}
-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: #3c763d;
-  background-color: #d0e9c6;
-}
-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: #3c763d;
-  border-color: #3c763d;
-}
-.list-group-item-info {
-  color: #31708f;
-  background-color: #d9edf7;
-}
-a.list-group-item-info,
-button.list-group-item-info {
-  color: #31708f;
-}
-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: #31708f;
-  background-color: #c4e3f3;
-}
-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: #31708f;
-  border-color: #31708f;
-}
-.list-group-item-warning {
-  color: #8a6d3b;
-  background-color: #fcf8e3;
-}
-a.list-group-item-warning,
-button.list-group-item-warning {
-  color: #8a6d3b;
-}
-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: #8a6d3b;
-  background-color: #faf2cc;
-}
-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: #8a6d3b;
-  border-color: #8a6d3b;
-}
-.list-group-item-danger {
-  color: #a94442;
-  background-color: #f2dede;
-}
-a.list-group-item-danger,
-button.list-group-item-danger {
-  color: #a94442;
-}
-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: #a94442;
-  background-color: #ebcccc;
-}
-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: #a94442;
-  border-color: #a94442;
-}
-.list-group-item-heading {
-  margin-top: 0;
-  margin-bottom: 5px;
-}
-.list-group-item-text {
-  margin-bottom: 0;
-  line-height: 1.3;
-}
-.panel {
-  margin-bottom: 20px;
-  background-color: #fff;
-  border: 1px solid transparent;
-  border-radius: 4px;
-  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
-          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
-}
-.panel-body {
-  padding: 15px;
-}
-.panel-heading {
-  padding: 10px 15px;
-  border-bottom: 1px solid transparent;
-  border-top-left-radius: 3px;
-  border-top-right-radius: 3px;
-}
-.panel-heading > .dropdown .dropdown-toggle {
-  color: inherit;
-}
-.panel-title {
-  margin-top: 0;
-  margin-bottom: 0;
-  font-size: 16px;
-  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: #f5f5f5;
-  border-top: 1px solid #ddd;
-  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-left-radius: 3px;
-  border-top-right-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-left-radius: 0;
-  border-top-right-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-right: 15px;
-  padding-left: 15px;
-}
-.panel > .table:first-child,
-.panel > .table-responsive:first-child > .table:first-child {
-  border-top-left-radius: 3px;
-  border-top-right-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-right-radius: 3px;
-  border-bottom-left-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 #ddd;
-}
-.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 {
-  margin-bottom: 0;
-  border: 0;
-}
-.panel-group {
-  margin-bottom: 20px;
-}
-.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 #ddd;
-}
-.panel-group .panel-footer {
-  border-top: 0;
-}
-.panel-group .panel-footer + .panel-collapse .panel-body {
-  border-bottom: 1px solid #ddd;
-}
-.panel-default {
-  border-color: #ddd;
-}
-.panel-default > .panel-heading {
-  color: #333;
-  background-color: #f5f5f5;
-  border-color: #ddd;
-}
-.panel-default > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #ddd;
-}
-.panel-default > .panel-heading .badge {
-  color: #f5f5f5;
-  background-color: #333;
-}
-.panel-default > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #ddd;
-}
-.panel-primary {
-  border-color: #337ab7;
-}
-.panel-primary > .panel-heading {
-  color: #fff;
-  background-color: #337ab7;
-  border-color: #337ab7;
-}
-.panel-primary > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #337ab7;
-}
-.panel-primary > .panel-heading .badge {
-  color: #337ab7;
-  background-color: #fff;
-}
-.panel-primary > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #337ab7;
-}
-.panel-success {
-  border-color: #d6e9c6;
-}
-.panel-success > .panel-heading {
-  color: #3c763d;
-  background-color: #dff0d8;
-  border-color: #d6e9c6;
-}
-.panel-success > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #d6e9c6;
-}
-.panel-success > .panel-heading .badge {
-  color: #dff0d8;
-  background-color: #3c763d;
-}
-.panel-success > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #d6e9c6;
-}
-.panel-info {
-  border-color: #bce8f1;
-}
-.panel-info > .panel-heading {
-  color: #31708f;
-  background-color: #d9edf7;
-  border-color: #bce8f1;
-}
-.panel-info > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #bce8f1;
-}
-.panel-info > .panel-heading .badge {
-  color: #d9edf7;
-  background-color: #31708f;
-}
-.panel-info > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #bce8f1;
-}
-.panel-warning {
-  border-color: #faebcc;
-}
-.panel-warning > .panel-heading {
-  color: #8a6d3b;
-  background-color: #fcf8e3;
-  border-color: #faebcc;
-}
-.panel-warning > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #faebcc;
-}
-.panel-warning > .panel-heading .badge {
-  color: #fcf8e3;
-  background-color: #8a6d3b;
-}
-.panel-warning > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #faebcc;
-}
-.panel-danger {
-  border-color: #ebccd1;
-}
-.panel-danger > .panel-heading {
-  color: #a94442;
-  background-color: #f2dede;
-  border-color: #ebccd1;
-}
-.panel-danger > .panel-heading + .panel-collapse > .panel-body {
-  border-top-color: #ebccd1;
-}
-.panel-danger > .panel-heading .badge {
-  color: #f2dede;
-  background-color: #a94442;
-}
-.panel-danger > .panel-footer + .panel-collapse > .panel-body {
-  border-bottom-color: #ebccd1;
-}
-.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;
-  bottom: 0;
-  left: 0;
-  width: 100%;
-  height: 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: #f5f5f5;
-  border: 1px solid #e3e3e3;
-  border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
-}
-.well blockquote {
-  border-color: #ddd;
-  border-color: rgba(0, 0, 0, .15);
-}
-.well-lg {
-  padding: 24px;
-  border-radius: 6px;
-}
-.well-sm {
-  padding: 9px;
-  border-radius: 3px;
-}
-.close {
-  float: right;
-  font-size: 21px;
-  font-weight: bold;
-  line-height: 1;
-  color: #000;
-  text-shadow: 0 1px 0 #fff;
-  filter: alpha(opacity=20);
-  opacity: .2;
-}
-.close:hover,
-.close:focus {
-  color: #000;
-  text-decoration: none;
-  cursor: pointer;
-  filter: alpha(opacity=50);
-  opacity: .5;
-}
-button.close {
-  -webkit-appearance: none;
-  padding: 0;
-  cursor: pointer;
-  background: transparent;
-  border: 0;
-}
-.modal-open {
-  overflow: hidden;
-}
-.modal {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 1050;
-  display: none;
-  overflow: hidden;
-  -webkit-overflow-scrolling: touch;
-  outline: 0;
-}
-.modal.fade .modal-dialog {
-  -webkit-transition: -webkit-transform .3s ease-out;
-       -o-transition:      -o-transform .3s ease-out;
-          transition:         transform .3s ease-out;
-  -webkit-transform: translate(0, -25%);
-      -ms-transform: translate(0, -25%);
-       -o-transform: translate(0, -25%);
-          transform: translate(0, -25%);
-}
-.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: #fff;
-  -webkit-background-clip: padding-box;
-          background-clip: padding-box;
-  border: 1px solid #999;
-  border: 1px solid rgba(0, 0, 0, .2);
-  border-radius: 6px;
-  outline: 0;
-  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
-          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
-}
-.modal-backdrop {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 1040;
-  background-color: #000;
-}
-.modal-backdrop.fade {
-  filter: alpha(opacity=0);
-  opacity: 0;
-}
-.modal-backdrop.in {
-  filter: alpha(opacity=50);
-  opacity: .5;
-}
-.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: 15px;
-}
-.modal-footer {
-  padding: 15px;
-  text-align: right;
-  border-top: 1px solid #e5e5e5;
-}
-.modal-footer .btn + .btn {
-  margin-bottom: 0;
-  margin-left: 5px;
-}
-.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, .5);
-            box-shadow: 0 5px 15px rgba(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: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 12px;
-  font-style: normal;
-  font-weight: normal;
-  line-height: 1.42857143;
-  text-align: left;
-  text-align: start;
-  text-decoration: none;
-  text-shadow: none;
-  text-transform: none;
-  letter-spacing: normal;
-  word-break: normal;
-  word-spacing: normal;
-  word-wrap: normal;
-  white-space: normal;
-  filter: alpha(opacity=0);
-  opacity: 0;
-
-  line-break: auto;
-}
-.tooltip.in {
-  filter: alpha(opacity=90);
-  opacity: .9;
-}
-.tooltip.top {
-  padding: 5px 0;
-  margin-top: -3px;
-}
-.tooltip.right {
-  padding: 0 5px;
-  margin-left: 3px;
-}
-.tooltip.bottom {
-  padding: 5px 0;
-  margin-top: 3px;
-}
-.tooltip.left {
-  padding: 0 5px;
-  margin-left: -3px;
-}
-.tooltip-inner {
-  max-width: 200px;
-  padding: 3px 8px;
-  color: #fff;
-  text-align: center;
-  background-color: #000;
-  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: #000;
-}
-.tooltip.top-left .tooltip-arrow {
-  right: 5px;
-  bottom: 0;
-  margin-bottom: -5px;
-  border-width: 5px 5px 0;
-  border-top-color: #000;
-}
-.tooltip.top-right .tooltip-arrow {
-  bottom: 0;
-  left: 5px;
-  margin-bottom: -5px;
-  border-width: 5px 5px 0;
-  border-top-color: #000;
-}
-.tooltip.right .tooltip-arrow {
-  top: 50%;
-  left: 0;
-  margin-top: -5px;
-  border-width: 5px 5px 5px 0;
-  border-right-color: #000;
-}
-.tooltip.left .tooltip-arrow {
-  top: 50%;
-  right: 0;
-  margin-top: -5px;
-  border-width: 5px 0 5px 5px;
-  border-left-color: #000;
-}
-.tooltip.bottom .tooltip-arrow {
-  top: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-width: 0 5px 5px;
-  border-bottom-color: #000;
-}
-.tooltip.bottom-left .tooltip-arrow {
-  top: 0;
-  right: 5px;
-  margin-top: -5px;
-  border-width: 0 5px 5px;
-  border-bottom-color: #000;
-}
-.tooltip.bottom-right .tooltip-arrow {
-  top: 0;
-  left: 5px;
-  margin-top: -5px;
-  border-width: 0 5px 5px;
-  border-bottom-color: #000;
-}
-.popover {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1060;
-  display: none;
-  max-width: 276px;
-  padding: 1px;
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 14px;
-  font-style: normal;
-  font-weight: normal;
-  line-height: 1.42857143;
-  text-align: left;
-  text-align: start;
-  text-decoration: none;
-  text-shadow: none;
-  text-transform: none;
-  letter-spacing: normal;
-  word-break: normal;
-  word-spacing: normal;
-  word-wrap: normal;
-  white-space: normal;
-  background-color: #fff;
-  -webkit-background-clip: padding-box;
-          background-clip: padding-box;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, .2);
-  border-radius: 6px;
-  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
-          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
-
-  line-break: auto;
-}
-.popover.top {
-  margin-top: -10px;
-}
-.popover.right {
-  margin-left: 10px;
-}
-.popover.bottom {
-  margin-top: 10px;
-}
-.popover.left {
-  margin-left: -10px;
-}
-.popover-title {
-  padding: 8px 14px;
-  margin: 0;
-  font-size: 14px;
-  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 {
-  content: "";
-  border-width: 10px;
-}
-.popover.top > .arrow {
-  bottom: -11px;
-  left: 50%;
-  margin-left: -11px;
-  border-top-color: #999;
-  border-top-color: rgba(0, 0, 0, .25);
-  border-bottom-width: 0;
-}
-.popover.top > .arrow:after {
-  bottom: 1px;
-  margin-left: -10px;
-  content: " ";
-  border-top-color: #fff;
-  border-bottom-width: 0;
-}
-.popover.right > .arrow {
-  top: 50%;
-  left: -11px;
-  margin-top: -11px;
-  border-right-color: #999;
-  border-right-color: rgba(0, 0, 0, .25);
-  border-left-width: 0;
-}
-.popover.right > .arrow:after {
-  bottom: -10px;
-  left: 1px;
-  content: " ";
-  border-right-color: #fff;
-  border-left-width: 0;
-}
-.popover.bottom > .arrow {
-  top: -11px;
-  left: 50%;
-  margin-left: -11px;
-  border-top-width: 0;
-  border-bottom-color: #999;
-  border-bottom-color: rgba(0, 0, 0, .25);
-}
-.popover.bottom > .arrow:after {
-  top: 1px;
-  margin-left: -10px;
-  content: " ";
-  border-top-width: 0;
-  border-bottom-color: #fff;
-}
-.popover.left > .arrow {
-  top: 50%;
-  right: -11px;
-  margin-top: -11px;
-  border-right-width: 0;
-  border-left-color: #999;
-  border-left-color: rgba(0, 0, 0, .25);
-}
-.popover.left > .arrow:after {
-  right: 1px;
-  bottom: -10px;
-  content: " ";
-  border-right-width: 0;
-  border-left-color: #fff;
-}
-.carousel {
-  position: relative;
-}
-.carousel-inner {
-  position: relative;
-  width: 100%;
-  overflow: hidden;
-}
-.carousel-inner > .item {
-  position: relative;
-  display: none;
-  -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 {
-    left: 0;
-    -webkit-transform: translate3d(100%, 0, 0);
-            transform: translate3d(100%, 0, 0);
-  }
-  .carousel-inner > .item.prev,
-  .carousel-inner > .item.active.left {
-    left: 0;
-    -webkit-transform: translate3d(-100%, 0, 0);
-            transform: translate3d(-100%, 0, 0);
-  }
-  .carousel-inner > .item.next.left,
-  .carousel-inner > .item.prev.right,
-  .carousel-inner > .item.active {
-    left: 0;
-    -webkit-transform: translate3d(0, 0, 0);
-            transform: translate3d(0, 0, 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;
-  bottom: 0;
-  left: 0;
-  width: 15%;
-  font-size: 20px;
-  color: #fff;
-  text-align: center;
-  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
-  background-color: rgba(0, 0, 0, 0);
-  filter: alpha(opacity=50);
-  opacity: .5;
-}
-.carousel-control.left {
-  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
-  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
-  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));
-  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
-  background-repeat: repeat-x;
-}
-.carousel-control.right {
-  right: 0;
-  left: auto;
-  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
-  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
-  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));
-  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
-  background-repeat: repeat-x;
-}
-.carousel-control:hover,
-.carousel-control:focus {
-  color: #fff;
-  text-decoration: none;
-  filter: alpha(opacity=90);
-  outline: 0;
-  opacity: .9;
-}
-.carousel-control .icon-prev,
-.carousel-control .icon-next,
-.carousel-control .glyphicon-chevron-left,
-.carousel-control .glyphicon-chevron-right {
-  position: absolute;
-  top: 50%;
-  z-index: 5;
-  display: inline-block;
-  margin-top: -10px;
-}
-.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;
-  font-family: serif;
-  line-height: 1;
-}
-.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%;
-  padding-left: 0;
-  margin-left: -30%;
-  text-align: center;
-  list-style: none;
-}
-.carousel-indicators li {
-  display: inline-block;
-  width: 10px;
-  height: 10px;
-  margin: 1px;
-  text-indent: -999px;
-  cursor: pointer;
-  background-color: #000 \9;
-  background-color: rgba(0, 0, 0, 0);
-  border: 1px solid #fff;
-  border-radius: 10px;
-}
-.carousel-indicators .active {
-  width: 12px;
-  height: 12px;
-  margin: 0;
-  background-color: #fff;
-}
-.carousel-caption {
-  position: absolute;
-  right: 15%;
-  bottom: 20px;
-  left: 15%;
-  z-index: 10;
-  padding-top: 20px;
-  padding-bottom: 20px;
-  color: #fff;
-  text-align: center;
-  text-shadow: 0 1px 2px rgba(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 {
-    right: 20%;
-    left: 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 {
-  display: table;
-  content: " ";
-}
-.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-right: auto;
-  margin-left: 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;
-  }
-}
-/*# sourceMappingURL=bootstrap.css.map */
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/project_profile.css b/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/project_profile.css
deleted file mode 100644 (file)
index 03527f0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-.container-custom {
-  max-width: 100% !important;
-}
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/search_form.css b/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/search_form.css
deleted file mode 100644 (file)
index 4598cff..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-input.search-input-rest
-{
-  font-weight: 400;
-  margin: 0px 0;
-  height: 30px;
-  padding: 10px 30px;
-    min-width: 90%;
-    max-width: 90%;
-  /*max-width: 500px;
-  */
-  border-radius: 5px;
-  border: 2px solid #333333;
-  box-shadow: 0 0 15px 1px rgba(0,0,0,0.50);
-  color: #333333;
-  font-size: 22px;
-}
-.material-search-custom {
-  left : -30px;
-
-  padding-left: 10px;
-}
-.form-group-custom {
-  width : 400px;
-  position: relative;
-  float: right;
-  left: -40%;
-}
-.form-control-custom {
-  padding-top: 10px;
-  padding-left: 50px;
-}
-input[type="search"]:focus:not([readonly]) {
-  transition: all 0s !important;
-  border-radius: 5px;
-  border: 2px solid #333333;
-  box-shadow: 0 0 15px 1px rgba(0,0,0,0.50);
-  color: #333333;
-}
-.gray {
-  background: rgb(249,249,249);
-}
-span.glyphicon.glyphicon-search.form-control-feedback,
-    div.form-group-custom i.material-icons {
-      top: 0.5em;
-      left: 16.0em;
-      cursor:pointer;
-      z-index: 30;
-      position: absolute;
-}
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/search_projects.css b/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/search_projects.css
deleted file mode 100644 (file)
index c000711..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-.card-shadow-custom {
-  box-shadow: 0 2px 3px 0 rgba(0,0,0,0.50);
-  border-bottom: 2px solid #8B19A2;
-}
-.row-custom {
-  display: flex;
-  flex-flow: row wrap;
-  width: 100%;
-  margin: 1em 1em 1em 1em;
-  padding-right: 20px;
-}
-.card-title-div-custom {
-  margin: 0.5em 0 0.5em 0;
-  text-align: left;
-  display: inline-block;
-}
-.card-title-span-custom {
-  margin: 0 0 0 2em;
-  display: inline-block;
-}
-.card-title-div-custom-right {
-  margin: 0.5em 0em 0.5em 0;
-  text-align: right;
-  display: inline-block;
-}
-.card-image-picture-custom {
-  margin: auto;
-}
-.collection .collection-item.active {
-  background-color: rgb(255,245,114);
-  text-decoration: none;
-  transition: none;
-}
-.collection a.collection-item:not(.active):hover {
-  background-color: rgb(255,245,114);
-  text-decoration: none;
-  transition: none;
-}
-.collection .collection-item {
-  padding: 1px 25px;
-  border-bottom: 0px;
-  transition: none;
-}
-.chip > a {
-  display: block;
-  text-decoration: none;
-  text-align: center;
-  display:inline-block;
-    font-size:13px;
-    font-weight:500;
-    color:rgba(0, 0, 0, 0.6) !important;
-    margin-right: 15px !important;
-    margin-left: 15px !important;
-    text-transform: none !important;
-}
-.chip > a:hover {
-  background-color: transparent;
-  text-decoration: none;
-  transition: none;
-}
-a.a-custom-more {
-  display: block;
-  text-decoration: none;
-  text-align: center;
-  display:inline-block;
-    font-size: 20px;
-    font-weight:500;
-    color:rgba(0, 0, 0, 0.6) !important;
-    margin-right: 15px !important;
-    text-transform: none !important;
-}
-a.a-custom-more:hover {
-  background-color: transparent;
-}
-.collection-custom {
-  margin: 0em 0em 0em 1em;
-}
-.card .row .card-action-custom {
-  margin-left: 20px;
-}
-.rating {
-  color: rgb(253,225,109) !important;
-}
-.filled-stars .star i {
-  color: rgb(253,225,109) !important;
-}
-.glyphicon-star-empty {
-  color: rgb(221,221,221);
-}
-.star {
-}
-span.glyphicon.glyphicon-search.form-control-feedback,
-    div.form-group-custom i.material-icons {
-      top: 0.5em;
-      left: 16.0em;
-      cursor:pointer;
-      z-index: 30;
-      position: absolute;
-}
-.card-image-custom {
-  display: flex;
-  flex-flow: column wrap;
-}
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/style.css b/utils/test/vnfcatalogue/VNF_Catalogue/public/stylesheets/style.css
deleted file mode 100644 (file)
index f5355ba..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-@import url('https://fonts.googleapis.com/css?family=Muli:300,400,600,700,800');
-*
-{
-  color: #333333;
-  font-family: 'Muli', sans-serif;
-}
-*:focus
-{
-    outline: none;
-}
-html,
-body
-{
-  margin: 0;
-  padding: 0;
-  background: #ffffff;
-  font-family: 'Muli', sans-serif;
-}
-header
-{
-  padding: 10px 35px 0 0px;
-}
-header ul
-{
-  list-style: none;
-  display: inline-block;
-}
-header ul li
-{
-  display: inline-block;
-}
-header .logo
-{
-  background: url(../images/logo.png) no-repeat;
-  background-size: cover;
-
-}
-header .brand-logo-extends
-{
-  background: url(../images/logo.png) no-repeat;
-  background-size: cover;
-  width: 154px;
-  height: 34px;
-  margin-top: 11%;
-  margin-right: 0%;
-  padding: 0;
-  position: relative !important;
-  /*margin-right: 20px;
-  margin-left: 0;
-  float: left;*/
-  /*display: inline-block;
-  */
-}
-
-nav
-{
-  height: 10px;
-}
-
-header ul li.links
-{
-  margin: 7px 10px 0 0;
-}
-header ul li > a,
-.content ul.most-menu li.items a
-{
-  color: #333333;
-  font-weight: 800;
-  font-size: 14px;
-  letter-spacing: 0.6px;
-  font-family: 'Muli', sans-serif;
-}
-header ul.navigation-right
-{
-  float: right;
-  padding-top: 8px;
-}
-header li.signup > a
-{
-  border: 2px solid #333333;
-  border-radius: 4px;
-  font-size: 14px;
-  font-weigt: 700;
-  padding: 2px 10px;
-}
-header li.signin > a
-{
-  border-bottom: 2px solid #333333;
-  font-size: 13px;
-  font-weight: 700;
-  padding: 0px 2px;
-}
-header li.option
-{
-  font-weight: 800;
-  padding: 0 10px;
-}
-header ul li > a:hover,
-header li.signin > a:hover,
-header li.signup > a:hover,
-header ul li > a:focus,
-header li.signin > a:focus,
-header li.signup > a:focus,
-.content ul.most-menu li a:hover,
-.content ul.most-menu li a:focus
-{
-  text-decoration: none;
-  cursor: pointer;
-  color: #333333;
-}
-header li.signup > a:hover
-{
-  background: #333333;
-  color: #ffffff;
-}
-.search-box
-{
-  text-align: center;
-  padding: 100px 0;
-}
-.search-box h1
-{
-  font-size: 30px;
-  letter-spacing: 2px;
-  color: #333333;
-  font-weight: 600;
-}
-form.search-form
-{
-  padding: 10px 20px;
-}
-form.search-form input.search-input
-{
-  font-weight: 400;
-  margin: 30px 0;
-  height: 80px;
-  padding: 10px 30px;
-  max-width: 800px;
-  width: 70%;
-  border-radius: 5px;
-  border: 2px solid #333333;
-  box-shadow: 0 0 15px 1px rgba(0,0,0,0.50);
-  color: #333333;
-  font-size: 22px;
-}
-
-form.search-form button.search-button
-{
-  padding: 18px 35px;
-  background: #FFF572;
-  border: 0;
-  box-shadow: 0 0 15px 1px #958F40;
-  border-radius: 1px;
-  font-size: 20px;
-  color: #393E41;
-  letter-spacing: 1px;
-  border-radius: 5px;
-  font-weight: 600;
-}
-form.search-form input:focus
-{
-  outline: none;
-}
-form.search-form input::-webkit-input-placeholder
-{
-  font-weight: 400;
-  letter-spacing: 1px;
-    color: #333333;
-}
-form.search-form input::-moz-placeholder
-{
-  font-weight: 400;
-  letter-spacing: 1px;
-    color: #333333;
-}
-form.search-form input:-moz-placeholder
-{
-  font-weight: 400;
-  letter-spacing: 5px;
-    color: #333333;
-}
-form.search-form input:-ms-input-placeholder
-{
-  font-weight: 400;
-  letter-spacing: 1px;
-    color: #333333;
-}
-.content
-{
-  height: 500px;
-  background: #f9f9f9;
-  padding: 10px 0;
-}
-.content ul.most-menu
-{
-  list-style: none;
-  text-align: center;
-  padding-bottom: 10px;
-}
-.content ul.most-menu li.items
-{
-  display: inline-block;
-  margin-right: 5px;
-  padding: 15px 25px;
-}
-.content ul.most-menu li.active
-{
-  /*background: #FFF572;*/
-}
-.content-box
-{
-  overflow: hidden;
-  padding: 20px 0 50px 0;
-  display: flex;
-  justify-content: center;
-  background: #FFFFFF;
-  box-shadow: 0 2px 3px 0 rgba(0,0,0,0.50);
-  border-bottom: 2px solid #8B19A2;
-  margin-bottom: 30px;
-}
-.content-data
-{
-  align-self: center;
-}
-.content-data h1.content-title
-{
-  font-size: 25px;
-  color: #000000;
-  letter-spacing: 1.2px;
-}
-.content-data .box
-{
-  padding: 10px 0;
-  height: 90px;
-  text-align: center;
-  border: 2px solid #4D4D4D;
-  border-radius: 2px;
-}
-.content-data .commit-icon
-{
-  width: 23px;
-  height: 16px;
-}
-.content-data .box h3.commits
-{
-  text-align: center;
-  font-size: 12px;
-  color: #333333;
-  letter-spacing: 0.03px;
-}
-.content-height-overwrite
-{
-  height: 110px;
-}
-.float-center-magic
-{
-  float: right;
-  position: relative;
-  left: -30%;
-}
-nav ul li:hover, nav ul li.active, nav ul li a.active, nav ul li a:hover {
-  background-color: rgb(255,245,114);
-}
-a:hover, a.active {
-  background-color: rgb(255,245,114);
-}
-footer
-{
-  font-size: 12px;
-  font-weight: 800;
-  color: #333333;
-  text-align: center;
-  padding: 20px;
-}
-.space-10
-{
-  height: 10px;
-}
-.space-30
-{
-  height: 100px;
-}
-input[type="search"]:focus:not([readonly]) {
-  transition: all 0s !important;
-  border-radius: 5px;
-  border: 2px solid #333333;
-  box-shadow: 0 0 15px 1px rgba(0,0,0,0.50);
-  color: #333333;
-}
-.gray {
-  background: rgb(249,249,249);
-}
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/public/uploads/logo.png b/utils/test/vnfcatalogue/VNF_Catalogue/public/uploads/logo.png
deleted file mode 100644 (file)
index fe18194..0000000
Binary files a/utils/test/vnfcatalogue/VNF_Catalogue/public/uploads/logo.png and /dev/null differ
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/routes/add_project.js b/utils/test/vnfcatalogue/VNF_Catalogue/routes/add_project.js
deleted file mode 100644 (file)
index 229620d..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var express = require('express');
-var router = express.Router();
-var multer = require('multer');
-
-
-var storage =   multer.diskStorage({
-  destination: function (req, file, callback) {
-    callback(null, './public/uploads');
-  },
-  filename: function (req, file, callback) {
-    console.log(file);
-    console.log(req.body);
-    callback(null, file.fieldname + '-' + Date.now() + '.jpg');
-  }
-});
-
-var fileFilter = function (req, file, cb) {
-  if (file.mimetype !== 'image/png') {
-    //req.fileValidationError = 'goes wrong on the mimetype';
-    cb(null, false);
-  } else {
-    cb(null, true);
-  }
-}
-
-var upload = multer({ fileFilter: fileFilter, storage : storage}).single('file_upload');
-
-
-router.post('/', function(req, res) {
-  upload(req,res,function(err) {
-        console.log(req.body);
-        console.log(req.file)
-        if(req.file == null && req.body['file_url'] != '') {
-            response = 'File Upload error: wrong Filetype';
-            res.status(500);
-            res.end(JSON.stringify({'error': response}));
-
-        }
-        if(err) {
-            console.log(err);
-            response = 'File Upload error: ' + err;
-            console.log(response);
-            //return res.end(req.fileValidationError);
-            res.status(500);
-            res.send({'error': response});
-            return;
-        }
-
-        console.log(req.file);
-        req.body['photo_url'] = (req.file) ? req.file['filename'] : 'logo.png';
-        console.log(req.body);
-
-        req.checkBody("vnf_name", "VNF Name must not be empty").notEmpty();
-        req.checkBody("repo_url", "Repository URL must not be empty").notEmpty();
-        req.checkBody("license", "Please select a License").notEmpty();
-        req.checkBody("opnfv_indicator", "Please select an OPNFV Indicator").notEmpty();
-        req.checkBody("repo_url", "Must be a Github URL").matches('.*github\.com.*');
-
-        var errors = req.validationErrors();
-        console.log(errors);
-
-        var response = '';  for(var i = 0; i < errors.length; i++) {
-            console.log(errors[i]['msg']);
-            response = response + errors[i]['msg'] + '; ';
-        }
-
-        if(errors) {    res.status(500);
-            res.send({'error': response});
-            return;
-        }
-
-        var vnf_details = req.body;
-        delete vnf_details.file_url;
-
-        db_pool.getConnection(function(err, connection) {
-            // Use the connection
-
-          sql_query = 'INSERT INTO photo(photo_url) values(\'' + req.body['photo_url'] + '\')\;SELECT LAST_INSERT_ID() photo_id';
-          // TODO look above query prone to sql_injections
-
-          console.log(sql_query);
-          connection.query(sql_query, function (error, results, fields) {
-             console.log('hola');
-             console.log(results[1][0].photo_id);
-              //connection.query(sql_query, vnf_details, function (error, results, fields) {
-             delete vnf_details.photo_url;
-             vnf_details['photo_id'] = results[1][0].photo_id;
-             sql_query = 'INSERT INTO vnf SET ?'
-               connection.query(sql_query, vnf_details, function (error, results, fields) {
-             // And done with the connection.
-             connection.release();
-             if (error) throw error;
-
-             // Handle error after the release.
-             res.end('{"success" : "Updated Successfully", "status" : 200}');
-             return;
-               // Don't use the connection here, it has been returned to the pool.
-               });
-          });
-        });
-
-
-  });
-
-});
-
-module.exports = router;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/routes/add_tag.js b/utils/test/vnfcatalogue/VNF_Catalogue/routes/add_tag.js
deleted file mode 100644 (file)
index 511f4cc..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var express = require('express');
-var router = express.Router();
-
-router.post('/', function(req, res) {
-  console.log(req.body);
-  req.checkBody("tag_name", "TAG Name must not be empty").notEmpty();
-
-  var errors = req.validationErrors();
-  console.log(errors);
-
-  var response = '';  for(var i = 0; i < errors.length; i++) {
-    console.log(errors[i]['msg']);
-    response = response + errors[i]['msg'] + '; ';
-  }
-
-  if(errors) {  res.status(500);
-    res.send({'error': response});
-    return;
-  }
-
-  var tag_details = req.body;
-
-  db_pool.getConnection(function(err, connection) {
-    // Use the connection
-    sql_query = 'INSERT INTO tag SET ?'
-    connection.query(sql_query, tag_details, function (error, results, fields) {
-        // And done with the connection.
-      res.end('{"success" : "Updated Successfully", "status" : 200}');
-      return;
-        connection.release();
-        // Handle error after the release.
-        if (error) throw error;
-        // Don't use the connection here, it has been returned to the pool.
-    });
-  });
-
-
-  res.end('{"success" : "Updated Successfully", "status" : 200}');
-  return;
-
-});
-
-module.exports = router;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/routes/index.js b/utils/test/vnfcatalogue/VNF_Catalogue/routes/index.js
deleted file mode 100644 (file)
index 950fcd5..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var express = require('express');
-var router = express.Router();
-
-/* GET VNF_Catalogue Home Page. */
-router.get('/', function(req, res) {
-  res.render('index', { title: 'Express' });
-});
-
-module.exports = router;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/routes/project_profile.js b/utils/test/vnfcatalogue/VNF_Catalogue/routes/project_profile.js
deleted file mode 100644 (file)
index be06642..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var express = require('express');
-var router = express.Router();
-
-router.get('/', function(req, res) {
-  var tags = req.param('tags');
-  console.log(tags);
-  res.render('project_profile', { title: 'Express' });
-});
-
-module.exports = router;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/routes/search_projects.js b/utils/test/vnfcatalogue/VNF_Catalogue/routes/search_projects.js
deleted file mode 100644 (file)
index 96f68db..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var express = require('express');
-var router = express.Router();
-var async = require('async');
-
-
-var renderer = function(res, err, results) {
-    console.log(results);
-    res.render('search_projects', { title: 'Express', json: results });
-}
-
-var get_tags = function(result, callback) {
-    db_pool.getConnection(function(err, connection) {
-        sql_query = 'select tag_name from tag where tag_id in (select tag_id from vnf_tags where vnf_id = ' + result['vnf_id'] + ') limit 5';
-        // TODO find why it works and not above
-        connection.query(sql_query, function (error, results, fields) {
-            console.log(results);
-            result['tags'] = results;
-            callback(null, result);
-            //connection.release();
-            if (error) throw error;
-        });
-    });
-}
-
-
-var get_images = function(result, callback) {
-    db_pool.getConnection(function(err, connection) {
-        sql_query = 'select photo_url from photo where photo_id = ' + result['photo_id'];
-        // TODO find why it works here and not when declared outside the method
-        console.log(sql_query);
-        connection.query(sql_query, function (error, results, fields) {
-            console.log(results[0].photo_url);
-            result['photo_url'] = results[0].photo_url;
-            callback(null, result);
-            //connection.release();
-            if (error) throw error;
-        });
-    });
-}
-
-var sql_data = function(tags, renderer, res) {
-    var tag_array = "\'" + tags.map(function (item) { return item; }).join("\',\'") + "\'";
-    console.log(tag_array);
-    var condition = '';
-    db_pool.getConnection(function(err, connection) {
-        sql_query = 'select tag_id from tag where tag_name in (' + tag_array + ')';
-        connection.query(sql_query, function (error, results, fields) {
-            condition = 'SELECT * FROM vnf as v';
-            for (var i in results) {
-                condition += (i == 0) ? ' WHERE ' : ' AND ';
-                condition += 'v.vnf_id IN (SELECT vnf_id from vnf_tags where tag_id = ' + results[i]['tag_id'] + ')';
-            }
-
-            connection.query(condition, function (error, results, fields) {
-                    console.log(results);
-                    async.map(results, get_images, function(error, results) {
-                        async.map(results, get_tags, renderer.bind(null, res));
-                    });
-                    //connection.release();
-                    if (error) throw error;
-            });
-
-            connection.release();
-            if (error) throw error;
-        });
-    });
-
-}
-
-router.get('/', function(req, res) {
-
-  console.log(typeof(req.param('tags')));
-  var tags = req.param('tags');
-
-  if(tags) {
-    tags = tags.toLowerCase().split(/[ ,]+/);
-    console.log(tags);
-    sql_data(tags, renderer, res);
-  } else {
-    res.render('search_projects', { title: 'Express', json: false});
-  }
-
-});
-
-module.exports = router;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/routes/search_tag.js b/utils/test/vnfcatalogue/VNF_Catalogue/routes/search_tag.js
deleted file mode 100644 (file)
index cbe8cae..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var express = require('express');
-var router = express.Router();
-
-/* Post Controller for Tag autocomplete form */
-router.get('/', function(req, res) {
-    tag_partial = req.param('key');
-    db_pool.getConnection(function(err, connection) {
-
-        sql_query = 'select tag_name from tag where tag_name like "%'+ tag_partial + '%" limit 5';
-        // TODO find why it works and not above
-        connection.query(sql_query, function (error, results, fields) {
-            console.log(results);
-
-            var data=[];
-            for(i = 0; i < results.length; i++) {
-                data.push(results[i].tag_name.replace(/\r?\n|\r/g, ''));
-            }
-            console.log(results);
-            connection.release();
-            res.end(JSON.stringify(results));
-
-            if (error) throw error;
-        });
-    });
-});
-
-module.exports = router;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/routes/search_vnf.js b/utils/test/vnfcatalogue/VNF_Catalogue/routes/search_vnf.js
deleted file mode 100644 (file)
index a5cf09c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var express = require('express');
-var router = express.Router();
-
-/* Post Controller for Search Vnf autocomplete form */
-router.get('/', function(req, res) {
-    tag_partial = req.param('key');
-    db_pool.getConnection(function(err, connection) {
-
-        sql_query = 'select vnf_name from vnf where vnf_name like "%'+ tag_partial + '%" limit 5';
-        // TODO find why it works and not above
-        connection.query(sql_query, function (error, results, fields) {
-            console.log(results);
-
-            var data=[];
-            for(i = 0; i < results.length; i++) {
-                data.push(results[i].vnf_name.replace(/\r?\n|\r/g, ''));
-            }
-            console.log(results);
-            connection.release();
-            res.end(JSON.stringify(results));
-
-            if (error) throw error;
-        });
-    });
-});
-
-module.exports = router;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/routes/vnf_tag_association.js b/utils/test/vnfcatalogue/VNF_Catalogue/routes/vnf_tag_association.js
deleted file mode 100644 (file)
index d1a3d72..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var express = require('express');
-var router = express.Router();
-
-/* Post controller for VNF_TAG Association */
-router.post('/', function(req, res) {
-  req.checkBody("tag_name", "TAG Name must not be empty").notEmpty();
-  req.checkBody("vnf_name", "VNF Name must not be empty").notEmpty();
-
-  var errors = req.validationErrors();
-  console.log(errors);
-
-  var response = '';  for(var i = 0; i < errors.length; i++) {
-    console.log(errors[i]['msg']);
-    response = response + errors[i]['msg'] + '; ';
-  }
-
-  if(errors) {  res.status(500);
-    res.send({'error': response});
-    return;
-  }
-
-  var tag_name = req.param('tag_name');
-  var vnf_name = req.param('vnf_name');
-
-  db_pool.getConnection(function(err, connection) {
-    // Use the connection
-    //sql_query = 'INSERT INTO tag SET ?'
-    sql_query = 'insert into vnf_tags(vnf_id, tag_id) values ((select vnf_id from vnf where vnf_name = \'' + vnf_name + '\'), (select tag_id from tag where tag_name = \'' + tag_name + '\'))';
-    console.log(sql_query);
-    connection.query(sql_query, function (error, results, fields) {
-        // And done with the connection.
-
-        connection.release();
-        res.end('{"success" : "Updated Successfully", "status" : 200}');
-
-        // Handle error after the release.
-        if (error) throw error;
-        // Don't use the connection here, it has been returned to the pool.
-    });
-  });
-
-  res.end('{"success" : "Updated Successfully", "status" : 200}');
-  //res.render('vnf_tag_association', { title: 'Express' });
-});
-
-module.exports = router;
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/views/add_project.jade b/utils/test/vnfcatalogue/VNF_Catalogue/views/add_project.jade
deleted file mode 100644 (file)
index dde8cfe..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-
-.search-box
-  script(src='/3rd_party/typeahead.js')
-  script(type='text/javascript', src='/javascripts/mode_edit.js')
-  .fixed-action-btn.fixed-action-btn_custom
-    a.btn-floating.btn-large.red
-      i.large.material-icons mode_edit
-    ul
-      li
-        a.btn-floating.red.tooltipped(href='#modal2', data-position='left', data-delay='50', data-tooltip='Add a TAG')
-          i.large.material-icons attach_file
-      li
-        a.btn-floating.green.tooltipped(href='#modal1', data-position='left', data-delay='50', data-tooltip='Add a VNF')
-          i.large.material-icons add
-      li
-        a.btn-floating.blue.tooltipped(href='#modal3', data-position='left', data-delay='50', data-tooltip='Add a TAG to a VNF')
-          i.large.material-icons share
-  #modal1.modal
-    .modal-content
-      h4.center
-        i.material-icons library_add
-        |         Add a VNF
-      .row
-        form#add_project_form.col.s12(action='/add_project', enctype='multipart/form-data', method='post')
-          .row.modal-form-row
-            .input-field.col.s12
-              input#vnf_name.validate(type='text', name='vnf_name')
-              label.left-align(for='vnf_name') Name
-          .row
-            .input-field.col.s12
-              input#repo_url.validate(type='text', name='repo_url')
-              label.left-align(for='repo_url') Github URL
-          .row
-            .input-field.col.s12
-              select#license
-                option(value='', name='license', disabled='', selected='') Choose the License
-                option(value='MIT') MIT
-                option(value='GPL') GPL
-                option(value='GPL_V2') GPL_V2
-                option(value='BSD') BSD
-                option(value='APACHE') APACHE
-              label License
-          .row
-            .input-field.col.s12
-              select#opnfv_indicator
-                option(value='', name='opnfv_indicator', disabled='', selected='') Choose the OPNFV Indicator
-                option(value='silver') silver
-                option(value='gold') gold
-                option(value='platinum') platinum
-              label OPNFV Indicator
-
-          .row
-            .file-field.input-field
-              .btn
-                span Photo (Optional)
-                input#file_upload(type='file', name='file_upload')
-              .file-path-wrapper
-                input.file-path.validate(type='text', name='file_url')
-
-          .row
-            .input-field.col.s12
-              input#submitter_id.validate(type='hidden', name='submitter_id', value=1)
-
-          .row
-            button#add_project_button.modal-action.modal-close.waves-effect.waves-light.btn.right
-              | Submit VNF
-              i.material-icons.right send
-  #modal2.modal
-    .modal-content
-      h4.center
-        i.material-icons library_add
-        |         Add a TAG
-      .row
-        form#add_tag_form.col.s12(action='/add_tag', method='post')
-          .row.modal-form-row
-            .input-field.col.s12
-              input#tag_name.validate(type='text', name='tag_name')
-              label.left-align(for='tag_name') Name
-          button#add_tag_button.modal-action.modal-close.waves-effect.waves-light.btn.right
-            | Submit TAG
-            i.material-icons.right send
-  #modal3.modal
-      h4.center
-        i.material-icons library_add
-        |         Add a TAG to a VNF
-      .row
-        form#add_vnf_tag_association_form.col.s12(action='/vnf_tag_association', method='post')
-
-          .row.modal-form-row.modal-form-row-custom
-            .input-field.col.s2 VNF Name
-            #scrollable-dropdown-menu.input-field.col.s4
-              input#vnf_name.typeahead(type='text', name='vnf_name')
-              //
-                label.left-align(for='tag_name') VNF Name
-            .input-field.col.s2 TAG Name
-            #scrollable-dropdown-menu.input-field.col.s4
-              input#tag_name.validate.typeahead(type='text', name='tag_name')
-              //
-                label.left-align(for='tag_name') TAG Name
-
-          button#add_vnf_tag_association_button.modal-action.modal-close.waves-effect.waves-light.btn.right
-            | Submit
-            i.material-icons.right send
-  style.
-    .select-dropdown{
-        overflow-y: auto !important;
-    }
-    .dropdown-content {
-        max-height: 200px !important;
-    }
-    .backdrop{
-       background-color: rgb(253,225,109);
-    }
-    .bg {
-    }
-    .modal-form-row-custom {
-      min-height: 200px !important;
-    }
-    #scrollable-dropdown-menu .tt-menu {
-      max-height: 150px;
-      overflow-y: auto;
-    }
-
-    .typeahead, .tt-query, .tt-hint {
-        border: 2px solid #CCCCCC;
-        border-radius: 8px 8px 8px 8px;
-        font-size: 24px;
-        height: 30px;
-        line-height: 30px;
-        outline: medium none;
-        padding: 8px 12px;
-        width: 396px;
-    }
-
-    .tt-query {
-        box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset;
-    }
-    .tt-hint {
-        color: #999999;
-    }
-    .tt-dropdown-menu {
-        background-color: #FFFFFF;
-        border: 1px solid rgba(0, 0, 0, 0.2);
-        border-radius: 8px 8px 8px 8px;
-        box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-        margin-top: 12px;
-        padding: 8px 0;
-        width: 200px;
-    }
-    .tt-suggestion {
-        font-size: 18px;
-        line-height: 24px;
-        padding: 3px 20px;
-    }
-    .tt-suggestion.tt-cursor {
-        background-color: #0097CF;
-        color: #FFFFFF;
-    }
-    .tt-suggestion p {
-        margin: 0;
-    }
-    .tt-dropdown-menu, .gist {
-        text-align: left;
-    }
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/views/error.jade b/utils/test/vnfcatalogue/VNF_Catalogue/views/error.jade
deleted file mode 100644 (file)
index 4f7fbca..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// 
-  Copyright (c) 2017 Kumar Rishabh and others.
-  All rights reserved. This program and the accompanying materials
-  are made available under the terms of the Apache License, Version 2.0
-  which accompanies this distribution, and is available at
-  http://www.apache.org/licenses/LICENSE-2.0
-extends layout
-
-block content
-  h1= message
-  h2= error.status
-  pre #{error.stack}
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/views/index.jade b/utils/test/vnfcatalogue/VNF_Catalogue/views/index.jade
deleted file mode 100644 (file)
index bf0cd14..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-extends layout
-
-//
-  Copyright (c) 2017 Kumar Rishabh and others.
-  All rights reserved. This program and the accompanying materials
-  are made available under the terms of the Apache License, Version 2.0
-  which accompanies this distribution, and is available at
-  http://www.apache.org/licenses/LICENSE-2.0
-block content
-  link(rel='stylesheet', href='/stylesheets/3rd_party/bootstrap.css')
-  .search-box
-    h1 VNF Catalogue
-    form.search-form
-      input.search-input(type='search', placeholder='Search...', id='Tags')
-      .space-10
-      button.search-button(type='submit', value='Search', id='Search') Search
-  .content.content-height-overwrite
-    nav.z-depth-0.transparent
-      .nav-wrapper
-        ul#nav-mobile.float-center-magic.hide-on-med-and-down.most-menu
-          li.items
-            a(href='#') Most Popular
-          li.items
-            a(href='#') Most Active
-          li.items
-            a(href='#') Most Active Contributions
-  .content
-    .container
-      .row
-        .box-container
-          .col-md-3
-            .content-box
-              .content-data
-                h1.content-title Beacon
-                .box
-                  img.commit-icon(src='/images/3rd_party/commits.png')
-                  h3.commits
-                    | 4,845
-                    br
-                    | commits
-        .col-md-3
-          .content-box
-            .content-data
-              h1.content-title Beacon
-              .box
-                img.commit-icon(src='/images/3rd_party/commits.png')
-                h3.commits
-                  | 4,845
-                  br
-                  | commits
-        .col-md-3
-          .content-box
-            .content-data
-              h1.content-title Beacon
-              .box
-                img.commit-icon(src='/images/3rd_party/commits.png')
-                h3.commits
-                  | 4,845
-                  br
-                  | commits
-        .col-md-3
-          .content-box
-            .content-data
-              h1.content-title Beacon
-              .box
-                img.commit-icon(src='/images/3rd_party/commits.png')
-                h3.commits
-                  | 4,845
-                  br
-                  | commits
-        .col-md-3
-          .content-box
-            .content-data
-              h1.content-title Beacon
-              .box
-                img.commit-icon(src='/images/3rd_party/commits.png')
-                h3.commits
-                  | 4,845
-                  br
-                  | commits
-        .col-md-3
-          .content-box
-            .content-data
-              h1.content-title Beacon
-              .box
-                img.commit-icon(src='/images/3rd_party/commits.png')
-                h3.commits
-                  | 4,845
-                  br
-                  | commits
-        .col-md-3
-          .content-box
-            .content-data
-              h1.content-title Beacon
-              .box
-                img.commit-icon(src='/images/3rd_party/commits.png')
-                h3.commits
-                  | 4,845
-                  br
-                  | commits
-        .col-md-3
-          .content-box
-            .content-data
-              h1.content-title Beacon
-              .box
-                img.commit-icon(src='/images/3rd_party/commits.png')
-                h3.commits
-                  | 4,845
-                  br
-                  | commits
-    footer
-      | © 2017 XYZ Company
-  style(type='text/css').
-    input[type="text"]:focus:not([readonly]) {
-      transition: all 0s !important;
-      border-radius: 5px;
-      border: 2px solid #333333;
-      box-shadow: 0 0 15px 1px rgba(0,0,0,0.50);
-      color: #333333;
-    }
-    .gray {
-      background: rgb(249,249,249);
-    }
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/views/layout.jade b/utils/test/vnfcatalogue/VNF_Catalogue/views/layout.jade
deleted file mode 100644 (file)
index 33c09e3..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-doctype html
-//
-  Copyright (c) 2017 Kumar Rishabh and others.
-  All rights reserved. This program and the accompanying materials
-  are made available under the terms of the Apache License, Version 2.0
-  which accompanies this distribution, and is available at
-  http://www.apache.org/licenses/LICENSE-2.0
-html(lang='en')
-html
-    head
-        title= title
-        link(rel='stylesheet', href='/3rd_party/materialize/css/materialize.css')
-        script(type='text/javascript', src='https://code.jquery.com/jquery-3.1.1.min.js')
-        script(src='/javascripts/global.js')
-        script(src='/3rd_party/materialize/js/materialize.js')
-        link(href='https://fonts.googleapis.com/icon?family=Material+Icons', rel='stylesheet')
-        link(rel='stylesheet', href='/stylesheets/style.css')
-    body
-        header
-          nav.transparent.z-depth-0
-            .nav-wrapper
-              a.button-collapse(href='#', data-activates='mobile-demo')
-                i.material-icons menu
-              ul#nav-mobile.left.hide-on-med-and-down
-                li
-                  a(href='#')
-                    img.left.brand-logo.brand-logo-extends
-                li
-                  a(href='#') Projects
-                li
-                  a(href='#') People
-                li
-                  a(href='#') About
-              ul#nav-mobile.right.hide-on-med-and-down
-                li.signup
-                  a(href='#') Sign up
-                li.option or
-                li.signin
-                  a(href='#') Sign in
-              ul#mobile-demo.side-nav
-                li
-                  a(href='#') Projects
-                li
-                  a(href='#') People
-                li
-                  a(href='#') About
-                li.signup
-                  a(href='#') Sign up
-                li.signin
-                  a(href='#') Sign in
-        block search
-        block add_project
-        block content
-
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/views/project_profile.jade b/utils/test/vnfcatalogue/VNF_Catalogue/views/project_profile.jade
deleted file mode 100644 (file)
index 7b37bd4..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-extends layout
-
-//
-  Copyright (c) 2017 Kumar Rishabh and others.
-  All rights reserved. This program and the accompanying materials
-  are made available under the terms of the Apache License, Version 2.0
-  which accompanies this distribution, and is available at
-  http://www.apache.org/licenses/LICENSE-2.0
-block search
-  include search
-block content
-  .content
-    .container.container-custom
-          .carousel
-            a.carousel-item(href='#one!')
-              img(src='http://lorempixel.com/250/250/nature/1')
-            a.carousel-item(href='#two!')
-              img(src='http://lorempixel.com/250/250/nature/2')
-            a.carousel-item(href='#three!')
-              img(src='http://lorempixel.com/250/250/nature/3')
-            a.carousel-item(href='#four!')
-              img(src='http://lorempixel.com/250/250/nature/4')
-            a.carousel-item(href='#five!')
-              img(src='http://lorempixel.com/250/250/nature/5')
-            .card.card-shadow-custom.horizontal
-            .row.row-custom
-          .col.s5.card-title-div-custom
-            span.card-title.card-title-span-custom Card Title
-          .col.s5.card-title-div-custom
-            i.material-icons grade
-            span.card-title PenguinScore: 42
-          .col.s2.card-title-div-custom-right
-            form(action='#')
-              input#search_result_1(type='checkbox')
-              label(for='search_result_1') Compare
-          //
-            <div class="card-action">
-            <a href="#">This is a link</a>
-            </div>
-          .col.s4.card-image.card-image-custom
-            img.card-image-picture-custom(src='/images/logo.png')
-          .col.s8.card-stacked
-            .card-content
-              p
-                .collection.collection-custom
-                  a.collection-item(href='#!')
-                    span
-                      i.material-icons code
-                      |                             Lines Of Code: 1.03M
-                  a.collection-item(href='#!')
-                    span
-                      i.material-icons code
-                      |                             Lines Of Code: 1.03M
-                  a.collection-item(href='#!')
-                    span
-                      i.material-icons code
-                      |                             Lines Of Code: 1.03M
-                  a.collection-item(href='#!')
-                    span
-                      i.material-icons code
-                      |                             Lines Of Code: 1.03M
-            .card-action
-              | Tags:
-              .chip
-                a.a-custom(href='#!') Tag1
-              .chip
-                a.a-custom(href='#!') Tag2
-              .chip
-                a.a-custom(href='#!') Tag3
-              .chip
-                a.a-custom(href='#!') Tag4
-              .chip
-                a.a-custom(href='#!') Tag5
-              a.a-custom-more(href='#!') more
-          .divider
-          .card-action-custom.col.s12.card-action
-            | License:
-            a(href='#') MIT
-            |                     Complexity:
-            a(href='#') Atomic
-  footer
-    | © 2017 XYZ Company
-    link(rel='stylesheet', href='/stylesheets/search_projects.css')
-
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/views/search.jade b/utils/test/vnfcatalogue/VNF_Catalogue/views/search.jade
deleted file mode 100644 (file)
index 77b2488..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-.search-box
-    link(rel='stylesheet', href='/stylesheets/search_form.css')
-    .form-group-custom.form-group.has-feedback
-      input.search-input-rest.form-control(type='search', placeholder='Search...', id='Tags')
-      i.material-icons search
\ No newline at end of file
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/views/search_projects.jade b/utils/test/vnfcatalogue/VNF_Catalogue/views/search_projects.jade
deleted file mode 100644 (file)
index ac91aa6..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-extends layout
-
-//
-  Copyright (c) 2017 Kumar Rishabh and others.
-  All rights reserved. This program and the accompanying materials
-  are made available under the terms of the Apache License, Version 2.0
-  which accompanies this distribution, and is available at
-  http://www.apache.org/licenses/LICENSE-2.0
-block search
-  include search
-block add_project
-  include add_project
-block content
-  .content
-    each key, index in json
-      .container.container-custom
-        .card.card-shadow-custom.horizontal
-          .row.row-custom
-            .col.s5.card-title-div-custom
-              span.card-title.card-title-span-custom #{key.vnf_name}
-            .col.s5.card-title-div-custom
-              i.material-icons grade
-              span.card-title PenguinScore: 42
-            .col.s2.card-title-div-custom-right
-              form(action='#')
-                input#search_result_1(type='checkbox', name='#{key.vnf_name}')
-                label(for='search_result_1') Compare
-            //
-              <div class="card-action">
-              <a href="#">This is a link</a>
-              </div>
-            .col.s4.card-image.card-image-custom
-              img.card-image-picture-custom(src='/uploads/#{key.photo_url}')
-            .col.s8.card-stacked
-              .card-content
-                p
-                  .collection.collection-custom
-                    a.collection-item(href='#!')
-                      span
-                        i.material-icons code
-                        |                             Lines Of Code: #{key.lines_of_code}
-                    a.collection-item(href='#!')
-                      span
-                        i.material-icons person
-                        |                             Number of Developers: #{key.no_of_developers}
-                    a.collection-item(href='#!')
-                      span
-                        i.material-icons star
-                        |                             Number of Stars: #{key.no_of_stars}
-                    a.collection-item(href='#!')
-                      span
-                        i.material-icons description
-                        |                             Number of Versions: #{key.versions}
-              .card-action
-                | Tags:
-                each tag, index in key.tags
-                  .chip
-                    a.a-custom(href='/search_projects?tags=#{tag.tag_name}') #{tag.tag_name}
-                //
-                  .chip
-                    a.a-custom(href='#!') tag1
-                  .chip
-                    a.a-custom(href='#!') Tag2
-                  .chip
-                    a.a-custom(href='#!') Tag3
-                  .chip
-                    a.a-custom(href='#!') Tag4
-                  .chip
-                    a.a-custom(href='#!') Tag5
-                a.a-custom-more(href='#!') more
-            .divider
-            .card-action-custom.col.s12.card-action
-              | License:
-              a(href='#') #{key.license}
-              | Complexity:
-              a(href='#') Atomic
-              | Activity:
-              a(href='#') Medium
-              | OPNFV Indicator:
-              a(href='#') #{key.opnfv_indicator}
-  footer
-    | © 2017 XYZ Company
-    link(rel='stylesheet', href='/stylesheets/search_projects.css')
diff --git a/utils/test/vnfcatalogue/VNF_Catalogue/views/vnf_tag_association.jade b/utils/test/vnfcatalogue/VNF_Catalogue/views/vnf_tag_association.jade
deleted file mode 100644 (file)
index c2e1160..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-doctype html
-//
-  Copyright (c) 2017 Kumar Rishabh and others.
-  All rights reserved. This program and the accompanying materials
-  are made available under the terms of the Apache License, Version 2.0
-  which accompanies this distribution, and is available at
-  http://www.apache.org/licenses/LICENSE-2.0
-html(lang='en')
-html
-  head
-    title= title
-    //
-      link(rel='stylesheet', href='/3rd_party/materialize/css/materialize.css')
-    script(type='text/javascript', src='https://code.jquery.com/jquery-3.1.1.min.js')
-    //
-      script(src='/javascripts/global.js')
-    //
-      script(src='/3rd_party/materialize/js/materialize.js')
-    link(href='https://fonts.googleapis.com/icon?family=Material+Icons', rel='stylesheet')
-    link(rel='stylesheet', href='/stylesheets/style.css')
-    script(src='/3rd_party/typeahead.js')
-    script(src='/javascripts/mode_edit.js')
-  body
-    h4.center
-    i.material-icons library_add
-    |         Add a TAG to a VNF
-    .row
-    form#add_tag_form.col.s12(action='/add_tag', method='post')
-      .row.modal-form-row
-          .input-field.col.s6 VNF Name
-          .input-field.col.s6 TAG Name
-      .row.modal-form-row
-        #scrollable-dropdown-menu.input-field.col.s6
-          input#tag_name.typeahead(type='text', name='tag_name')
-          //
-            label.left-align(for='tag_name') VNF Name
-
-        .input-field.col.s6
-          input#tag_name.validate(type='text', name='vnf_name')
-          //
-            label.left-align(for='tag_name') TAG Name
-      .row.modal-form-row
-          .input-field.col.s6
-          .input-field.col.s6
-      .row.modal-form-row
-      button#add_tag_button.modal-action.modal-close.waves-effect.waves-light.btn.right
-        | Submit
-        i.material-icons.right send
-style.
-  #scrollable-dropdown-menu .tt-menu {
-    max-height: 150px;
-    overflow-y: auto;
-  }
-
-  .typeahead, .tt-query, .tt-hint {
-      border: 2px solid #CCCCCC;
-      border-radius: 8px 8px 8px 8px;
-      font-size: 24px;
-      height: 30px;
-      line-height: 30px;
-      outline: medium none;
-      padding: 8px 12px;
-      width: 396px;
-  }
-  .typeahead {
-      background-color: #FFFFFF;
-  }
-  .typeahead:focus {
-      border: 2px solid #0097CF;
-  }
-  .tt-query {
-      box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset;
-  }
-  .tt-hint {
-      color: #999999;
-  }
-  .tt-dropdown-menu {
-      background-color: #FFFFFF;
-      border: 1px solid rgba(0, 0, 0, 0.2);
-      border-radius: 8px 8px 8px 8px;
-      box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-      margin-top: 12px;
-      padding: 8px 0;
-      width: 422px;
-  }
-  .tt-suggestion {
-      font-size: 18px;
-      line-height: 24px;
-      padding: 3px 20px;
-  }
-  .tt-suggestion.tt-cursor {
-      background-color: #0097CF;
-      color: #FFFFFF;
-  }
-  .tt-suggestion p {
-      margin: 0;
-  }
-  .tt-dropdown-menu, .gist {
-      text-align: left;
-  }
-  /*
-  html {
-      overflow-y: scroll;
-  }
-  .container {
-      margin: 0 auto;
-      max-width: 750px;
-      text-align: center;
-  }
-
-  html {
-      color: #333333;
-      font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
-      font-size: 18px;
-      line-height: 1.2;
-  }
-  .title, .example-name {
-      font-family: Prociono;
-  }
-  p {
-      margin: 0 0 10px;
-  }
-  .title {
-      font-size: 64px;
-      margin: 20px 0 0;
-  }
-  .example {
-      padding: 30px 0;
-  }
-  .example-name {
-      font-size: 32px;
-      margin: 20px 0;
-  }
-  .demo {
-      margin: 50px 0;
-      position: relative;
-  }
-  */
-  /*
-  .gist {
-      font-size: 14px;
-  }
-  .example-twitter-oss .tt-suggestion {
-      padding: 8px 20px;
-  }
-  .example-twitter-oss .tt-suggestion + .tt-suggestion {
-      border-top: 1px solid #CCCCCC;
-  }
-  .example-twitter-oss .repo-language {
-      float: right;
-      font-style: italic;
-  }
-  .example-twitter-oss .repo-name {
-      font-weight: bold;
-  }
-  .example-twitter-oss .repo-description {
-      font-size: 14px;
-  }
-  .example-sports .league-name {
-      border-bottom: 1px solid #CCCCCC;
-      margin: 0 20px 5px;
-      padding: 3px 0;
-  }
-  .example-arabic .tt-dropdown-menu {
-      text-align: right;
-  }
-  */
diff --git a/utils/test/vnfcatalogue/cronjobs/README.md b/utils/test/vnfcatalogue/cronjobs/README.md
deleted file mode 100644 (file)
index cf27ff8..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# CRONJOB Directory
-
-## Helper to setup cronjob to fill the vnf table
-
-There are two important parameters that need to be set in github.js
-before running cronjob.
-
-
-```
-   access_token : generate an access token from github account for accessing
-   the github apis. This is necessary as the non access token limit tends to 
-   be 50 api calls per hour.
-   delta : the threshold between the last update of the row of the vnf table
-   and current time. It is measured in seconds.
-```
-
-Enter the details namely username and password in the **database.js**.
-Then setup the cronjob by putting the following line in the crontab
-
-In the crontab
-
-```bash
-    node github
-```
diff --git a/utils/test/vnfcatalogue/cronjobs/database.js b/utils/test/vnfcatalogue/cronjobs/database.js
deleted file mode 100644 (file)
index a1d926e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-var mysql = require('mysql');
-
-var pool = mysql.createPool({
-  host: 'localhost',
-  user: 'myuser',
-  password: 'mypassword',
-  database: 'vnf_catalogue',
-  connectionLimit: 50,
-  supportBigNumbers: true,
-  multipleStatements: true,
-  dateStrings: 'date'
-});
-
-exports.pool = pool;
diff --git a/utils/test/vnfcatalogue/cronjobs/github.js b/utils/test/vnfcatalogue/cronjobs/github.js
deleted file mode 100644 (file)
index 05cc6c1..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-// Important Add your access token here default rate of github is limited to 60 API calls per hour
-var access_token = '*';
-// Important set the delta threshold for repo details updation. For instance if the threshold is
-// set to 1 day(60 * 60 * 24), the cronjob will only update the row if the difference between current
-// time and last_updated time stamp of a repo is greater than one day
-var delta = 60 * 60 * 24;
-
-
-var github = require('octonode');
-db_pool = require('./database').pool;
-async = require('async');
-
-var current_time = Math.floor(new Date().getTime() / 1000);//toISOString().slice(0, 19).replace('T', ' ');
-console.log(current_time);
-
-var get_val_from_header = function(header_link) {
-    // small hack by parsing the header and setting per_page = 1, hence no pagination fetch required
-    result_intermediate = header_link.split(';');
-    result_intermediate = result_intermediate[result_intermediate.length - 2];
-    var reg = /&page=([0-9].*)>/g;
-    var match = reg.exec(result_intermediate);
-    return parseInt(match[1]);
-}
-
-var get_stargazers = function(result, ghrepo, primary_callback, cb) {
-    ghrepo.stargazers({per_page: 1}, function(err, data, headers) {
-    //console.log(JSON.stringify(data));
-        try {
-            result['no_of_stars'] = get_val_from_header(headers['link']);
-            cb(null, result, ghrepo, primary_callback);
-        } catch(err) {
-            result['no_of_stars'] = null;
-            cb(null, result, ghrepo, primary_callback);
-        }
-    });
-}
-
-var get_branches = function(result, ghrepo, primary_callback, cb) {
-    ghrepo.branches({per_page: 1}, function(err, data, headers) {
-        try {
-            result['versions'] = get_val_from_header(headers['link']);
-            cb(null, result, ghrepo, primary_callback);
-        } catch(err) {
-            result['versions'] = null;
-            cb(null, result, ghrepo, primary_callback);
-        }
-    });
-}
-
-var get_contributors = function(result, ghrepo, primary_callback, cb) {
-    ghrepo.contributors({per_page: 1}, function(err, data, headers) {
-        try {
-            result['no_of_developers'] = get_val_from_header(headers['link']);
-            cb(null, result, primary_callback);
-        } catch(err) {
-            result['no_of_developers'] = null;
-            cb(null, result, primary_callback);
-
-        }
-    });
-}
-
-var get_lines_of_code = function(result, cb) {
-    //    #TODO
-}
-
-var secondary_callback = function (err, result, primary_callback) {
-    console.log(result);
-    if((result['last_updated'] == null) || (current_time - result['last_updated'] > delta)) {
-        db_pool.getConnection(function(err, connection) {
-            //Use the connection
-            var last_updated = current_time;
-            var no_of_stars = result['no_of_stars'];
-            var versions = result['versions'];
-            var no_of_developers = result['no_of_developers'];
-            sql_query = 'update vnf set last_updated = FROM_UNIXTIME(' + last_updated;
-            sql_query += '), no_of_stars =  ' + no_of_stars + ', versions = ' + versions;
-            sql_query += ', no_of_developers = ' + no_of_developers + ' where vnf_id = ';
-            sql_query += result['vnf_id'];
-            console.log(sql_query);
-            connection.query(sql_query, function (error, results, fields) {
-                if (error) throw error;
-                //And done with the connection.
-                primary_callback(null, result['vnf_id'] + ' updated');
-                connection.release();
-                // Handle error after the release.
-                // Don't use the connection here, it has been returned to the pool.
-            });
-        });
-    } else {
-        primary_callback(null, result['vnf_id'] + ' not updated');
-    }
-}
-
-var get_stats = function(vnf_details, callback) {
-    repo = vnf_details['repo_url'];
-    repo = repo.split("/");
-    github_id = repo[repo.length - 2] + '/' + repo[repo.length - 1];
-
-    var async = require('async');
-    var client = github.client(access_token);
-    var ghrepo = client.repo(github_id);
-
-    result = {}
-    result['vnf_id'] = vnf_details['vnf_id'];
-    result['last_updated'] = vnf_details['last_updated'];
-
-    async.waterfall([
-            async.apply(get_stargazers, result, ghrepo, callback),
-            get_branches,
-            get_contributors,
-            //get_lines_of_code,
-        ], secondary_callback);
-}
-
-db_pool.getConnection(function(err, connection) {
-    sql_query = 'select vnf_id, repo_url, UNIX_TIMESTAMP(last_updated) last_updated from vnf';
-    console.log(sql_query);
-    connection.query(sql_query, function (error, results, fields) {
-        if (error) throw error;
-        async.map(results, get_stats, function(error, results) {
-            //console.log(results);
-            console.log(results);
-            process.exit();
-
-        });
-    });
-});
-
diff --git a/utils/test/vnfcatalogue/helpers/README.md b/utils/test/vnfcatalogue/helpers/README.md
deleted file mode 100644 (file)
index 6c0ca78..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# Helper Directory
-
-## Helper to migrate database
-
-First make sure nodejs and mysql are installed. Then use
-
-```bash
-npm install bookshelf mysql knex when lodash --save
-```
-
-Create a database named **vnf_catalogue**.
-Enter the mysql credentials in migrate.js.
-
-Then use
-
-```bash
-node migrate
-```
-
-If successful the script will return success message. The current script is
-idempotent is nature, if run twice it will just return error and write nothing.
-
diff --git a/utils/test/vnfcatalogue/helpers/migrate.js b/utils/test/vnfcatalogue/helpers/migrate.js
deleted file mode 100644 (file)
index 3f4d892..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh(penguinRaider) and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-
-var knex = require('knex')({
-    client: 'mysql',
-    connection: {
-        host     : process.env.DB_HOST,
-        user     : process.env.DB_USER,
-        password : process.env.DB_PASSWORD,
-        database : process.env.DB_DATABASE,
-        charset  : 'utf8'
-    }
-});
-var Schema = require('./schema');
-var sequence = require('when/sequence');
-var _ = require('lodash');
-function createTable(tableName) {
-    return knex.schema.createTable(tableName, function (table) {
-    var column;
-    var columnKeys = _.keys(Schema[tableName]);
-    _.each(columnKeys, function (key) {
-        if (Schema[tableName][key].type === 'text' && Schema[tableName][key].hasOwnProperty('fieldtype')) {
-        column = table[Schema[tableName][key].type](key, Schema[tableName][key].fieldtype);
-        }
-        else if (Schema[tableName][key].type === 'enum' && Schema[tableName][key].hasOwnProperty('values') && Schema[tableName][key].nullable === true) {
-        console.log(Schema[tableName][key].values);
-        column = table[Schema[tableName][key].type](key, Schema[tableName][key].values).nullable();
-        }
-        else if (Schema[tableName][key].type === 'enum' && Schema[tableName][key].hasOwnProperty('values')) {
-        console.log(Schema[tableName][key].values);
-        column = table[Schema[tableName][key].type](key, Schema[tableName][key].values).notNullable();
-        }
-        else if (Schema[tableName][key].type === 'string' && Schema[tableName][key].hasOwnProperty('maxlength')) {
-        column = table[Schema[tableName][key].type](key, Schema[tableName][key].maxlength);
-        }
-        else {
-        column = table[Schema[tableName][key].type](key);
-        }
-        if (Schema[tableName][key].hasOwnProperty('nullable') && Schema[tableName][key].nullable === true) {
-        column.nullable();
-        }
-        else {
-        column.notNullable();
-        }
-        if (Schema[tableName][key].hasOwnProperty('primary') && Schema[tableName][key].primary === true) {
-        column.primary();
-        }
-        if (Schema[tableName][key].hasOwnProperty('unique') && Schema[tableName][key].unique) {
-        column.unique();
-        }
-        if (Schema[tableName][key].hasOwnProperty('unsigned') && Schema[tableName][key].unsigned) {
-        column.unsigned();
-        }
-        if (Schema[tableName][key].hasOwnProperty('references')) {
-        column.references(Schema[tableName][key].references);
-        }
-        if (Schema[tableName][key].hasOwnProperty('defaultTo')) {
-        column.defaultTo(Schema[tableName][key].defaultTo);
-        }
-    });
-    });
-}
-function createTables () {
-    var tables = [];
-    var tableNames = _.keys(Schema);
-    tables = _.map(tableNames, function (tableName) {
-    return function () {
-        return createTable(tableName);
-    };
-    });
-    return sequence(tables);
-}
-createTables()
-.then(function() {
-    console.log('Tables created!!');
-    process.exit(0);
-})
-.catch(function (error) {
-    throw error;
-});
diff --git a/utils/test/vnfcatalogue/helpers/schema.js b/utils/test/vnfcatalogue/helpers/schema.js
deleted file mode 100644 (file)
index 4a7559a..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Kumar Rishabh(penguinRaider) and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Apache License, Version 2.0
- * which accompanies this distribution, and is available at
- * http://www.apache.org/licenses/LICENSE-2.0
- *******************************************************************************/
-var Schema = {
-    photo: {
-        photo_id: {type: 'increments', nullable: false, primary: true},
-        photo_url: {type: 'string', maxlength: 254, nullable: false}
-    },
-    user: {
-        user_id: {type: 'increments', nullable: false, primary: true},
-        user_name: {type: 'string', maxlength: 254, nullable: false},
-        password: {type: 'string', maxlength: 150, nullable: false},
-        email_id: {type: 'string', maxlength: 254, nullable: false, unique: true, validations: {isEmail: true}},
-        photo_id: {type: 'integer', nullable: true, unsigned: true, references: 'photo.photo_id'},
-        company: {type: 'string', maxlength: 254, nullable: false},
-        introduction: {type: 'string', maxlength: 510, nullable: false},
-        last_login: {type: 'dateTime', nullable: true},
-        created_at: {type: 'dateTime', nullable: false},
-    },
-    vnf: {
-        vnf_id: {type: 'increments', nullable: false, primary: true},
-        vnf_name: {type: 'string', maxlength: 254, nullable: false},
-        repo_url: {type: 'string', maxlength: 254, nullable: false},
-        photo_id: {type: 'integer', nullable: true, unsigned: true, references: 'photo.photo_id'},
-        submitter_id: {type: 'integer', nullable: false, unsigned: true, references: 'user.user_id'},
-        lines_of_code: {type: 'integer', nullable: true, unsigned: true},
-        versions: {type: 'integer', nullable: true, unsigned: true},
-        no_of_developers: {type: 'integer', nullable: true, unsigned: true},
-        no_of_stars: {type: 'integer', nullable: true, unsigned: true},
-        license: {type: 'enum', nullable: false, values: ['MIT', 'GPL', 'GPL_V2', 'BSD', 'APACHE']},
-        opnfv_indicator: {type: 'enum', nullable: false, values: ['gold', 'silver', 'platinum']},
-        complexity: {type: 'enum', nullable: true, values: ['low', 'medium', 'high']},
-        activity: {type: 'enum', nullable: true, values: ['low', 'medium', 'high']},
-        last_updated: {type: 'dateTime', nullable: true},
-    },
-    tag: {
-        tag_id: {type: 'increments', nullable: false, primary: true},
-        tag_name: {type: 'string', maxlength: 150, nullable: false}
-    },
-    vnf_tags: {
-        vnf_tag_id: {type: 'increments', nullable: false, primary: true},
-        tag_id: {type: 'integer', nullable: false, unsigned: true, references: 'tag.tag_id'},
-        vnf_id: {type: 'integer', nullable: false, unsigned: true, references: 'vnf.vnf_id'},
-    },
-    vnf_contributors: {
-        vnf_contributors_id: {type: 'increments', nullable: false, primary: true},
-        user_id: {type: 'integer', nullable: false, unsigned: true, references: 'user.user_id'},
-        vnf_id: {type: 'integer', nullable: false, unsigned: true, references: 'vnf.vnf_id'},
-        created_at: {type: 'dateTime', nullable: false},
-    }
-};
-module.exports = Schema;
diff --git a/utils/upload-artifact.sh b/utils/upload-artifact.sh
new file mode 100644 (file)
index 0000000..b66cdb7
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/bash
+# SPDX-license-identifier: Apache-2.0
+##############################################################################
+# Copyright (c) 2016 Orange and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+set -e
+set -o pipefail
+
+export PATH=$PATH:/usr/local/bin/
+
+# 2 paramters
+# - $1: the source directory where the files to be uploaded are located
+# - $2: the target on artifact http://artifact.opnfv.org/<project>/$2
+#   if not set, default value is <project>/docs
+project=$PROJECT
+if [ -z "$2" ]
+  then
+      artifact_dir="$project/docs"
+  else
+      artifact_dir="$project/$2"
+fi
+DIRECTORY="$1"
+
+
+# check that the API doc directory does exist before pushing it to artifact
+if [ ! -d "$DIRECTORY" ]; then
+    echo "Directory to be uploaded "$DIRECTORY" does not exist"
+    exit 1
+fi
+set +e
+gsutil&>/dev/null
+if [ $? != 0 ]; then
+    echo "Not possible to push results to artifact: gsutil not installed"
+    exit 1
+else
+    gsutil ls gs://artifacts.opnfv.org/"$project"/ &>/dev/null
+    if [ $? != 0 ]; then
+        echo "Not possible to push results to artifact: gsutil not installed."
+        exit 1
+    else
+        echo "Uploading file(s) to artifact $artifact_dir"
+        gsutil -m cp -r "$DIRECTORY"/* gs://artifacts.opnfv.org/"$artifact_dir"/ >/dev/null 2>&1
+    fi
+fi